source: rtems/cpukit/score/src/smp.c @ 2f6108f9

4.115
Last change on this file since 2f6108f9 was 2f6108f9, checked in by Sebastian Huber <sebastian.huber@…>, on May 28, 2013 at 8:58:19 AM

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: 4.9 KB
Line 
1/**
2 *  @file
3 *
4 *  @brief SMP Support
5 *  @ingroup Score
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#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <rtems/system.h>
22#include <rtems/bspsmp.h>
23#include <rtems/score/smp.h>
24#include <rtems/score/thread.h>
25
26#if defined(RTEMS_DEBUG)
27  #include <rtems/bspIo.h>
28#endif
29
30void rtems_smp_secondary_cpu_initialize( void )
31{
32  int              self = bsp_smp_processor_id();
33  Per_CPU_Control *per_cpu = &_Per_CPU_Information[ self ];
34  Thread_Control  *heir;
35
36  #if defined(RTEMS_DEBUG)
37    printk( "Made it to %d -- ", self );
38  #endif
39
40  _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING );
41
42  _Per_CPU_Wait_for_state( per_cpu, PER_CPU_STATE_BEGIN_MULTITASKING );
43
44  _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_UP );
45
46  /*
47   *  The Scheduler will have selected the heir thread for each CPU core.
48   *  Now we have been requested to perform the first context switch.  So
49   *  force a switch to the designated heir and make it executing on
50   *  THIS core.
51   */
52  heir = per_cpu->heir;
53  per_cpu->executing = heir;
54
55  /*
56   * Threads begin execution in the _Thread_Handler() function.   This function
57   * will call _Thread_Enable_dispatch().
58   */
59  _Thread_Disable_dispatch();
60
61  _CPU_Context_switch_to_first_task_smp( &heir->Registers );
62}
63
64void rtems_smp_process_interrupt( void )
65{
66  int              self = bsp_smp_processor_id();
67  Per_CPU_Control *per_cpu = &_Per_CPU_Information[ self ];
68  uint32_t         message;
69  ISR_Level        level;
70
71
72  level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock );
73  message = per_cpu->message;
74  per_cpu->message = 0;
75  _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level );
76
77  #if defined(RTEMS_DEBUG)
78    {
79      void *sp = __builtin_frame_address(0);
80      if ( !(message & RTEMS_BSP_SMP_SHUTDOWN) ) {
81        printk( "ISR on CPU %d -- (0x%02x) (0x%p)\n", self, message, sp );
82        if ( message & RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY )
83          printk( "context switch necessary\n" );
84        if ( message & RTEMS_BSP_SMP_SIGNAL_TO_SELF )
85          printk( "signal to self\n" );
86        if ( message & RTEMS_BSP_SMP_SHUTDOWN )
87          printk( "shutdown\n" );
88      }
89 
90      printk( "Dispatch level %d\n", _Thread_Dispatch_get_disable_level() );
91    }
92  #endif
93
94  if ( message & RTEMS_BSP_SMP_SHUTDOWN ) {
95    _ISR_Disable_on_this_core( level );
96
97    while ( _Thread_Dispatch_decrement_disable_level() != 0 ) {
98      /* Release completely */
99    }
100
101    _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_SHUTDOWN );
102    while(1)
103      ;
104    /* does not continue past here */
105  }
106}
107
108void _SMP_Send_message( int cpu, uint32_t message )
109{
110  Per_CPU_Control *per_cpu = &_Per_CPU_Information[ cpu ];
111  ISR_Level level;
112
113  #if defined(RTEMS_DEBUG)
114    if ( message & RTEMS_BSP_SMP_SIGNAL_TO_SELF )
115      printk( "Send 0x%x to %d\n", message, cpu );
116  #endif
117
118  level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock );
119  per_cpu->message |= message;
120  _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level );
121
122  bsp_smp_interrupt_cpu( cpu );
123}
124
125void _SMP_Broadcast_message( uint32_t message )
126{
127  int self = bsp_smp_processor_id();
128  int ncpus = _SMP_Processor_count;
129  int cpu;
130
131  for ( cpu = 0 ; cpu < ncpus ; ++cpu ) {
132    if ( cpu != self ) {
133      Per_CPU_Control *per_cpu = &_Per_CPU_Information[ cpu ];
134      ISR_Level level = _SMP_lock_spinlock_simple_Obtain( &per_cpu->lock );
135      per_cpu->message |= message;
136      _SMP_lock_spinlock_simple_Release( &per_cpu->lock, level );
137    }
138  }
139
140  bsp_smp_broadcast_interrupt();
141}
142
143void _SMP_Request_other_cores_to_perform_first_context_switch( void )
144{
145  int self = bsp_smp_processor_id();
146  int ncpus = _SMP_Processor_count;
147  int cpu;
148
149  for ( cpu = 0 ; cpu < ncpus ; ++cpu ) {
150    if ( cpu != self ) {
151      _Per_CPU_Change_state(
152        &_Per_CPU_Information[ cpu ],
153        PER_CPU_STATE_BEGIN_MULTITASKING
154      );
155    }
156  }
157}
158
159void _SMP_Request_other_cores_to_dispatch( void )
160{
161  if ( _System_state_Is_up( _System_state_Get() ) ) {
162    int self = bsp_smp_processor_id();
163    int ncpus = _SMP_Processor_count;
164    int cpu;
165
166    for ( cpu = 0 ; cpu < ncpus ; ++cpu ) {
167      const Per_CPU_Control *per_cpu = &_Per_CPU_Information[ cpu ];
168
169      if (
170        cpu != self
171          && per_cpu->state == PER_CPU_STATE_UP
172          && per_cpu->dispatch_necessary
173      ) {
174        _SMP_Send_message( cpu, RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY );
175      }
176    }
177  }
178}
179
180void _SMP_Request_other_cores_to_shutdown( void )
181{
182  int self = bsp_smp_processor_id();
183  int ncpus = _SMP_Processor_count;
184  int cpu;
185
186  _SMP_Broadcast_message( RTEMS_BSP_SMP_SHUTDOWN );
187
188  for ( cpu = 0 ; cpu < ncpus ; ++cpu ) {
189    if ( cpu != self ) {
190      _Per_CPU_Wait_for_state(
191        &_Per_CPU_Information[ cpu ],
192        PER_CPU_STATE_SHUTDOWN
193      );
194    }
195  }
196}
Note: See TracBrowser for help on using the repository browser.