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

4.115
Last change on this file since d4dc7c8 was d4dc7c8, checked in by Jennifer Averett <Jennifer.Averett@…>, on 05/26/11 at 18:07:07

2011-05-26 Jennifer Averett <Jennifer.Averett@…>

PR 1796/cpukit

  • sapi/src/exshutdown.c, score/include/rtems/score/percpu.h, score/include/rtems/score/smp.h, score/src/smp.c, score/src/threaddispatch.c, score/src/threadhandler.c: Added SMP interprocess communications.
  • Property mode set to 100644
File size: 7.3 KB
RevLine 
[06dcaf0]1/*
2 *  COPYRIGHT (c) 1989-2011.
3 *  On-Line Applications Research Corporation (OAR).
4 *
5 *  The license and distribution terms for this file may be
6 *  found in the file LICENSE in this distribution or at
7 *  http://www.rtems.com/license/LICENSE.
8 *
9 *  $Id$
10 */
11
12#if HAVE_CONFIG_H
13#include "config.h"
14#endif
15
16#include <rtems/system.h>
17#include <rtems/bspsmp.h>
[0d5a9f1]18#include <rtems/score/smp.h>
[06dcaf0]19#include <rtems/score/thread.h>
20
21#if defined(RTEMS_SMP)
[d4dc7c8]22  #define RTEMS_DEBUG
23#endif
[06dcaf0]24
[d4dc7c8]25#if defined(RTEMS_DEBUG)
[06dcaf0]26  #include <rtems/bspIo.h>
27#endif
28
[d4dc7c8]29/*
30 *  Process request to switch to the first task on a secondary core.
31 */
[06dcaf0]32void rtems_smp_run_first_task(int cpu)
33{
34  Thread_Control *heir;
35
36  /*
[d4dc7c8]37   *  The Scheduler will have selected the heir thread for each CPU core.
38   *  Now we have been requested to perform the first context switch.  So
39   *  force a switch to the designated heir and make it executing on
40   *  THIS core.
[06dcaf0]41   */
[d4dc7c8]42  heir              = _Thread_Heir;
[06dcaf0]43  _Thread_Executing = heir;
[d4dc7c8]44
[06dcaf0]45  _CPU_Context_switch_to_first_task_smp( &heir->Registers );
46}
47
[d4dc7c8]48/*
49 *  Process request to initialize this secondary core.
50 */
[06dcaf0]51void rtems_smp_secondary_cpu_initialize(void)
52{
53  int cpu;
54
55  cpu = bsp_smp_processor_id();
56
57  bsp_smp_secondary_cpu_initialize(cpu);
58
[d4dc7c8]59  #if defined(RTEMS_DEBUG)
[06dcaf0]60    printk( "Made it to %d -- ", cpu );
61  #endif
62
63  /*
64   *  Inform the primary CPU that this secondary CPU is initialized
65   *  and ready to dispatch to the first thread it is supposed to
66   *  execute when the primary CPU is ready.
67   */
68  _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_INITIALIZED;
69
70  /*
[d4dc7c8]71   *  With this secondary core out of reset, we can wait for the
72   *  request to switch to the first task.
73   *
74   *  XXX When SMP ISR code is complete, do we want interrupts on
75   *  XXX or off at this point?
[06dcaf0]76   */
77  _ISR_Set_level( 0 );
[d4dc7c8]78  while(1) {
79    bsp_smp_wait_for(
80      (volatile unsigned int *)&_Per_CPU_Information[cpu].message,
81      RTEMS_BSP_SMP_FIRST_TASK,
82      10000
83    );
84  }
[06dcaf0]85}
86
[d4dc7c8]87/*
88 *  Process an interrupt processor interrupt which indicates a request
89 *  from another core.
90 */
[06dcaf0]91void rtems_smp_process_interrupt(void)
92{
93  int        cpu;
94  uint32_t   message;
95  ISR_Level  level;
96
97  cpu = bsp_smp_processor_id();
98
[d4dc7c8]99  level = _SMP_lock_Simple_Spinlock_Obtain( &_Per_CPU_Information[cpu].lock );
100  message = _Per_CPU_Information[cpu].message;
[06dcaf0]101
[d4dc7c8]102  #if defined(RTEMS_DEBUG)
[06dcaf0]103    {
104      void *sp = __builtin_frame_address(0);
[d4dc7c8]105      if ( !(message & RTEMS_BSP_SMP_SHUTDOWN) ) {
106        printk( "ISR on CPU %d -- (0x%02x) (0x%p)\n", cpu, message, sp );
107        if ( message & RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY )
108          printk( "context switch necessary\n" );
109        if ( message & RTEMS_BSP_SMP_SIGNAL_TO_SELF )
110          printk( "signal to self\n" );
111        if ( message & RTEMS_BSP_SMP_SHUTDOWN )
112          printk( "shutdown\n" );
113        if ( message & RTEMS_BSP_SMP_FIRST_TASK )
114          printk( "switch to first task\n" );
115      }
116 
117      printk( "Dispatch level %d\n", _Thread_Dispatch_get_disable_level() );
[06dcaf0]118    }
119  #endif
120
121  if ( message & RTEMS_BSP_SMP_FIRST_TASK ) {
[d4dc7c8]122    /*
123     * XXX Thread dispatch disable level at this point will have to be
124     * XXX revisited when Interrupts on SMP is addressed.
125     */
126    _Thread_Dispatch_disable_level--; /* undo ISR code */
[06dcaf0]127    _Per_CPU_Information[cpu].isr_nest_level = 0;
[d4dc7c8]128    _Per_CPU_Information[cpu].message &= ~message;
129    _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_UP;
130
131    _SMP_lock_Simple_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
132    _Thread_Disable_dispatch();
[06dcaf0]133    rtems_smp_run_first_task(cpu);
134    /* does not return */
135  }
136
137  if ( message & RTEMS_BSP_SMP_SHUTDOWN ) {
[d4dc7c8]138    /*
139     * XXX Thread dispatch disable level at this point will have to be
140     * XXX revisited when Interrupts on SMP is addressed.
141     */
142    _Per_CPU_Information[cpu].message &= ~message;
143    _SMP_lock_Simple_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
144
145    _Thread_Dispatch_disable_level--; /* undo ISR code */
[06dcaf0]146    _Per_CPU_Information[cpu].isr_nest_level = 0;
147    _Per_CPU_Information[cpu].state = RTEMS_BSP_SMP_CPU_SHUTDOWN;
148    _ISR_Disable( level );
149    while(1)
150      ;
151    /* does not continue past here */
152  }
153
154  if ( message & RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY ) {
[d4dc7c8]155    #if defined(RTEMS_DEBUG)
156      printk( "switch needed\n" );
157    #endif
158    /*
159     * XXX Thread dispatch disable level at this point will have to be
160     * XXX revisited when Interrupts on SMP is addressed.
161     */
162    _Per_CPU_Information[cpu].message &= ~message;
163    _SMP_lock_Simple_Spinlock_Release( &_Per_CPU_Information[cpu].lock, level );
[06dcaf0]164  }
165}
166
[d4dc7c8]167/*
168 *  Send an interrupt processor request to another cpu.
169 */
170void _SMP_Send_message(
[06dcaf0]171  int       cpu,
172  uint32_t  message
173)
174{
175  ISR_Level level;
176
[a8d7e2ab]177  level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock );
[06dcaf0]178    _Per_CPU_Information[cpu].message |= message;
[a8d7e2ab]179  _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level );
[06dcaf0]180  bsp_smp_interrupt_cpu( cpu );
181}
182
[d4dc7c8]183/*
184 *  Send interrupt processor request to all other nodes
185 */
186void _SMP_Broadcast_message(
[06dcaf0]187  uint32_t  message
188)
189{
190  int        dest_cpu;
191  int        cpu;
192  ISR_Level  level;
193
194  cpu = bsp_smp_processor_id();
195
196  for ( dest_cpu=0 ; dest_cpu <  _SMP_Processor_count; dest_cpu++ ) {
197    if ( cpu == dest_cpu )
198      continue;
[a8d7e2ab]199    level = _SMP_lock_spinlock_simple_Obtain( &_Per_CPU_Information[cpu].lock );
[06dcaf0]200      _Per_CPU_Information[dest_cpu].message |= message;
[a8d7e2ab]201    _SMP_lock_spinlock_simple_Release( &_Per_CPU_Information[cpu].lock, level );
[06dcaf0]202  }
203  bsp_smp_broadcast_interrupt();
204}
[d4dc7c8]205
206/*
207 *  Send interrupt processor requests to perform first context switch
208 */
209void _SMP_Request_other_cores_to_perform_first_context_switch(void)
210{
211  int    cpu;
212
213  for (cpu=1 ; cpu < _SMP_Processor_count ; cpu++ ) {
214    _SMP_Send_message( cpu, RTEMS_BSP_SMP_FIRST_TASK );
215    while (_Per_CPU_Information[cpu].state != RTEMS_BSP_SMP_CPU_UP ) {
216      bsp_smp_wait_for(
217        (volatile unsigned int *)&_Per_CPU_Information[cpu].state,
218        RTEMS_BSP_SMP_CPU_UP,
219        10000
220      );
221    }
222  }
223}
224
225/*
226 *  Send message to other cores requesting them to perform
227 *  a thread dispatch operation.
228 */
229void _SMP_Request_other_cores_to_dispatch(void)
230{
231  int i;
232  int cpu;
233
234  cpu = bsp_smp_processor_id();
235
236  if ( !_System_state_Is_up (_System_state_Current) )
237    return;
238  for (i=1 ; i < _SMP_Processor_count ; i++ ) {
239    if ( cpu == i )
240      continue;
241    if ( _Per_CPU_Information[i].state != RTEMS_BSP_SMP_CPU_UP )
242      continue;
243    if ( !_Per_CPU_Information[i].dispatch_necessary )
244      continue;
245    _SMP_Send_message( i, RTEMS_BSP_SMP_CONTEXT_SWITCH_NECESSARY );
246    bsp_smp_wait_for(
247      (volatile unsigned int *)&_Per_CPU_Information[i].message,
248      0,
249      10000
250    );
251  }
252}
253
254/*
255 *  Send message to other cores requesting them to shutdown.
256 */
257void _SMP_Request_other_cores_to_shutdown(void)
258{
259  bool allDown;
260  int  ncpus;
261  int  cpu;
262
263  ncpus = _SMP_Processor_count;
264
265  _SMP_Broadcast_message( RTEMS_BSP_SMP_SHUTDOWN );
266
267  allDown = true;
268  for (cpu=1 ; cpu<ncpus ; cpu++ ) {
269     bsp_smp_wait_for(
270       (unsigned int *)&_Per_CPU_Information[cpu].state,
271       RTEMS_BSP_SMP_CPU_SHUTDOWN,
272       10000
273    );
274    if ( _Per_CPU_Information[cpu].state != RTEMS_BSP_SMP_CPU_SHUTDOWN )
275      allDown = false;
276  }
277  if ( !allDown )
278    printk( "All CPUs not successfully shutdown -- timed out\n" );
279  #if (RTEMS_DEBUG)
280    else
281      printk( "All CPUs shutdown successfully\n" );
282  #endif
283}
Note: See TracBrowser for help on using the repository browser.