source: rtems/cpukit/score/include/rtems/score/percpu.h @ 2f6108f9

4.115
Last change on this file since 2f6108f9 was 2f6108f9, checked in by Sebastian Huber <sebastian.huber@…>, on 05/28/13 at 08:58:19

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().

  • Property mode set to 100644
File size: 8.4 KB
Line 
1/**
2 *  @file  rtems/score/percpu.h
3 *
4 *  This include file defines the per CPU information required
5 *  by RTEMS.
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.com/license/LICENSE.
15 */
16
17#ifndef _RTEMS_PERCPU_H
18#define _RTEMS_PERCPU_H
19
20#include <rtems/score/cpu.h>
21
22#ifdef ASM
23  #include <rtems/asm.h>
24#else
25  #include <rtems/score/isrlevel.h>
26  #include <rtems/score/timestamp.h>
27  #if defined(RTEMS_SMP)
28    #include <rtems/score/smplock.h>
29  #endif
30
31  /*
32   * NOTE: This file MUST be included on non-smp systems as well
33   *       in order to define bsp_smp_processor_id.
34   */
35  #include <rtems/bspsmp.h>
36#endif
37
38/**
39 *  @defgroup PerCPU RTEMS Per CPU Information
40 *
41 *  @ingroup Score
42 *
43 *  This defines the per CPU state information required by RTEMS
44 *  and the BSP.  In an SMP configuration, there will be multiple
45 *  instances of this data structure -- one per CPU -- and the
46 *  current CPU number will be used as the index.
47 */
48
49/**@{*/
50
51#ifdef __cplusplus
52extern "C" {
53#endif
54
55#ifndef ASM
56#include <rtems/score/timestamp.h>
57
58#ifndef __THREAD_CONTROL_DEFINED__
59#define __THREAD_CONTROL_DEFINED__
60typedef struct Thread_Control_struct Thread_Control;
61#endif
62
63#ifdef RTEMS_SMP
64
65typedef enum {
66  /**
67   * @brief The per CPU controls are initialized to zero.
68   *
69   * In this state the only valid field of the per CPU controls for secondary
70   * processors is the per CPU state.  The secondary processors should perform
71   * their basic initialization now and change into the
72   * PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING state once this is complete.
73   *
74   * The owner of the per CPU state field is the secondary processor in this
75   * state.
76   */
77  PER_CPU_STATE_BEFORE_INITIALIZATION,
78
79  /**
80   * @brief Secondary processor is ready to begin multitasking.
81   *
82   * The secondary processor performed its basic initialization and is ready to
83   * receive inter-processor interrupts.  Interrupt delivery must be disabled
84   * in this state, but requested inter-processor interrupts must be recorded
85   * and must be delivered once the secondary processor enables interrupts for
86   * the first time.  The main processor will wait for all secondary processors
87   * to change into this state.  In case a secondary processor does not reach
88   * this state the system will not start.  The secondary processors wait now
89   * for a change into the PER_CPU_STATE_BEGIN_MULTITASKING state set by the
90   * main processor once all secondary processors reached the
91   * PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING state.
92   *
93   * The owner of the per CPU state field is the main processor in this state.
94   */
95  PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING,
96
97  /**
98   * @brief Multitasking begin of secondary processor is requested.
99   *
100   * The main processor completed system initialization and is about to perform
101   * a context switch to its heir thread.  Secondary processors should now
102   * issue a context switch to the heir thread.  This normally enables
103   * interrupts on the processor for the first time.
104   *
105   * The owner of the per CPU state field is the secondary processor in this
106   * state.
107   */
108  PER_CPU_STATE_BEGIN_MULTITASKING,
109
110  /**
111   * @brief Normal multitasking state.
112   *
113   * The owner of the per CPU state field is the secondary processor in this
114   * state.
115   */
116  PER_CPU_STATE_UP,
117
118  /**
119   * @brief This is the terminal state.
120   *
121   * The owner of the per CPU state field is the secondary processor in this
122   * state.
123   */
124  PER_CPU_STATE_SHUTDOWN
125} Per_CPU_State;
126
127#endif /* RTEMS_SMP */
128
129/**
130 *  @brief Per CPU Core Structure
131 *
132 *  This structure is used to hold per core state information.
133 */
134typedef struct {
135  #if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
136      (CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
137    /**
138     * This contains a pointer to the lower range of the interrupt stack for
139     * this CPU.  This is the address allocated and freed.
140     */
141    void  *interrupt_stack_low;
142
143    /**
144     * This contains a pointer to the interrupt stack pointer for this CPU.
145     * It will be loaded at the beginning on an ISR.
146     */
147    void  *interrupt_stack_high;
148  #endif
149
150  /**
151   *  This contains the current interrupt nesting level on this
152   *  CPU.
153   */
154  uint32_t isr_nest_level;
155
156  /** This is set to true when this CPU needs to run the dispatcher. */
157  volatile bool dispatch_necessary;
158
159  /** This is the thread executing on this CPU. */
160  Thread_Control *executing;
161
162  /** This is the heir thread for this this CPU. */
163  Thread_Control *heir;
164
165  /** This is the idle thread for this CPU. */
166  Thread_Control *idle;
167
168  /** This is the time of the last context switch on this CPU. */
169  Timestamp_Control time_of_last_context_switch;
170
171  #if defined(RTEMS_SMP)
172    /** This element is used to lock this structure */
173    SMP_lock_spinlock_simple_Control  lock;
174
175    /**
176     *  This is the request for the interrupt.
177     *
178     *  @note This may become a chain protected by atomic instructions.
179     */
180    uint32_t message;
181
182    /**
183     * @brief Indicates the current state of the CPU.
184     *
185     * This field is not protected by a lock.
186     *
187     * @see _Per_CPU_Change_state() and _Per_CPU_Wait_for_state().
188     */
189    Per_CPU_State state;
190  #endif
191} Per_CPU_Control;
192#endif
193
194#if defined(ASM) || defined(_RTEMS_PERCPU_DEFINE_OFFSETS)
195
196#if (CPU_ALLOCATE_INTERRUPT_STACK == TRUE) || \
197    (CPU_HAS_SOFTWARE_INTERRUPT_STACK == TRUE)
198  /*
199   *  If this CPU target lets RTEMS allocates the interrupt stack, then
200   *  we need to have places in the per CPU table to hold them.
201   */
202  #define PER_CPU_INTERRUPT_STACK_LOW \
203    0
204  #define PER_CPU_INTERRUPT_STACK_HIGH \
205    PER_CPU_INTERRUPT_STACK_LOW + CPU_SIZEOF_POINTER
206  #define PER_CPU_END_STACK             \
207    PER_CPU_INTERRUPT_STACK_HIGH + CPU_SIZEOF_POINTER
208
209  #define INTERRUPT_STACK_LOW \
210    (SYM(_Per_CPU_Information) + PER_CPU_INTERRUPT_STACK_LOW)
211  #define INTERRUPT_STACK_HIGH \
212    (SYM(_Per_CPU_Information) + PER_CPU_INTERRUPT_STACK_HIGH)
213#else
214  #define PER_CPU_END_STACK \
215    0
216#endif
217
218/*
219 *  These are the offsets of the required elements in the per CPU table.
220 */
221#define PER_CPU_ISR_NEST_LEVEL \
222  PER_CPU_END_STACK
223#define PER_CPU_DISPATCH_NEEDED \
224  PER_CPU_ISR_NEST_LEVEL + 4
225
226#define ISR_NEST_LEVEL \
227  (SYM(_Per_CPU_Information) + PER_CPU_ISR_NEST_LEVEL)
228#define DISPATCH_NEEDED \
229  (SYM(_Per_CPU_Information) + PER_CPU_DISPATCH_NEEDED)
230
231#endif /* defined(ASM) || defined(_RTEMS_PERCPU_DEFINE_OFFSETS) */
232
233#ifndef ASM
234
235/**
236 *  @brief Set of Per CPU Core Information
237 *
238 *  This is an array of per CPU core information.
239 */
240extern Per_CPU_Control _Per_CPU_Information[] CPU_STRUCTURE_ALIGNMENT;
241
242#if defined(RTEMS_SMP)
243/**
244 *  @brief Set of Pointers to Per CPU Core Information
245 *
246 *  This is an array of pointers to each CPU's per CPU data structure.
247 *  It should be simpler to retrieve this pointer in assembly language
248 *  that to calculate the array offset.
249 */
250extern Per_CPU_Control *_Per_CPU_Information_p[];
251
252/**
253 *  @brief Initialize SMP Handler
254 *
255 *  This method initialize the SMP Handler.
256 */
257void _SMP_Handler_initialize(void);
258
259/**
260 *  @brief Allocate and Initialize Per CPU Structures
261 *
262 *  This method allocates and initialize the per CPU structure.
263 */
264void _Per_CPU_Initialize(void);
265
266void _Per_CPU_Change_state(
267  Per_CPU_Control *per_cpu,
268  Per_CPU_State new_state
269);
270
271void _Per_CPU_Wait_for_state(
272  const Per_CPU_Control *per_cpu,
273  Per_CPU_State desired_state
274);
275
276#endif
277
278/*
279 * On a non SMP system, the bsp_smp_processor_id is defined to 0.
280 * Thus when built for non-SMP, there should be no performance penalty.
281 */
282#define _Thread_Heir \
283  _Per_CPU_Information[bsp_smp_processor_id()].heir
284#define _Thread_Executing \
285  _Per_CPU_Information[bsp_smp_processor_id()].executing
286#define _Thread_Idle \
287  _Per_CPU_Information[bsp_smp_processor_id()].idle
288#define _ISR_Nest_level \
289  _Per_CPU_Information[bsp_smp_processor_id()].isr_nest_level
290#define _CPU_Interrupt_stack_low \
291  _Per_CPU_Information[bsp_smp_processor_id()].interrupt_stack_low
292#define _CPU_Interrupt_stack_high \
293  _Per_CPU_Information[bsp_smp_processor_id()].interrupt_stack_high
294#define _Thread_Dispatch_necessary \
295  _Per_CPU_Information[bsp_smp_processor_id()].dispatch_necessary
296#define _Thread_Time_of_last_context_switch \
297  _Per_CPU_Information[bsp_smp_processor_id()].time_of_last_context_switch
298
299#endif  /* ASM */
300
301#ifdef __cplusplus
302}
303#endif
304
305/**@}*/
306
307#endif
308/* end of include file */
Note: See TracBrowser for help on using the repository browser.