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 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: 4.9 KB
RevLine 
[e655f7e]1/**
2 *  @file
3 *
4 *  @brief SMP Support
5 *  @ingroup Score
6 */
7
[06dcaf0]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>
[0d5a9f1]23#include <rtems/score/smp.h>
[06dcaf0]24#include <rtems/score/thread.h>
25
[d4dc7c8]26#if defined(RTEMS_DEBUG)
[06dcaf0]27  #include <rtems/bspIo.h>
28#endif
29
[2f6108f9]30void rtems_smp_secondary_cpu_initialize( void )
[06dcaf0]31{
[2f6108f9]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 );
[dad36c52]43
[2f6108f9]44  _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_UP );
[06dcaf0]45
46  /*
[d4dc7c8]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
[2f6108f9]49   *  force a switch to the designated heir and make it executing on
[d4dc7c8]50   *  THIS core.
[06dcaf0]51   */
[2f6108f9]52  heir = per_cpu->heir;
53  per_cpu->executing = heir;
[06dcaf0]54
55  /*
[2f6108f9]56   * Threads begin execution in the _Thread_Handler() function.   This function
57   * will call _Thread_Enable_dispatch().
[06dcaf0]58   */
[2f6108f9]59  _Thread_Disable_dispatch();
[dad36c52]60
[2f6108f9]61  _CPU_Context_switch_to_first_task_smp( &heir->Registers );
[06dcaf0]62}
63
[2f6108f9]64void rtems_smp_process_interrupt( void )
[06dcaf0]65{
[2f6108f9]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;
[06dcaf0]70
71
[2f6108f9]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 );
[06dcaf0]76
[d4dc7c8]77  #if defined(RTEMS_DEBUG)
[06dcaf0]78    {
79      void *sp = __builtin_frame_address(0);
[d4dc7c8]80      if ( !(message & RTEMS_BSP_SMP_SHUTDOWN) ) {
[2f6108f9]81        printk( "ISR on CPU %d -- (0x%02x) (0x%p)\n", self, message, sp );
[d4dc7c8]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() );
[06dcaf0]91    }
92  #endif
93
94  if ( message & RTEMS_BSP_SMP_SHUTDOWN ) {
[2f6108f9]95    _ISR_Disable_on_this_core( level );
[d4dc7c8]96
[2f6108f9]97    while ( _Thread_Dispatch_decrement_disable_level() != 0 ) {
98      /* Release completely */
99    }
[dad36c52]100
[2f6108f9]101    _Per_CPU_Change_state( per_cpu, PER_CPU_STATE_SHUTDOWN );
[06dcaf0]102    while(1)
103      ;
104    /* does not continue past here */
105  }
106}
107
[2f6108f9]108void _SMP_Send_message( int cpu, uint32_t message )
[06dcaf0]109{
[2f6108f9]110  Per_CPU_Control *per_cpu = &_Per_CPU_Information[ cpu ];
[06dcaf0]111  ISR_Level level;
112
[dad36c52]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
[2f6108f9]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
[06dcaf0]122  bsp_smp_interrupt_cpu( cpu );
123}
124
[2f6108f9]125void _SMP_Broadcast_message( uint32_t message )
[06dcaf0]126{
[2f6108f9]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    }
[06dcaf0]138  }
[2f6108f9]139
[06dcaf0]140  bsp_smp_broadcast_interrupt();
141}
[d4dc7c8]142
[2f6108f9]143void _SMP_Request_other_cores_to_perform_first_context_switch( void )
[d4dc7c8]144{
[2f6108f9]145  int self = bsp_smp_processor_id();
146  int ncpus = _SMP_Processor_count;
147  int cpu;
[d4dc7c8]148
[2f6108f9]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    }
[d4dc7c8]156  }
157}
158
[2f6108f9]159void _SMP_Request_other_cores_to_dispatch( void )
[d4dc7c8]160{
[2f6108f9]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    }
[d4dc7c8]177  }
178}
179
[2f6108f9]180void _SMP_Request_other_cores_to_shutdown( void )
[d4dc7c8]181{
[2f6108f9]182  int self = bsp_smp_processor_id();
183  int ncpus = _SMP_Processor_count;
184  int cpu;
[d4dc7c8]185
186  _SMP_Broadcast_message( RTEMS_BSP_SMP_SHUTDOWN );
187
[2f6108f9]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    }
[d4dc7c8]195  }
196}
Note: See TracBrowser for help on using the repository browser.