source: rtems/c/src/lib/libbsp/sparc/leon3/smp/smp_leon3.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: 3.5 KB
Line 
1/**
2 *  @file
3 *
4 *  LEON3 SMP BSP Support
5 */
6
7/*
8 *  COPYRIGHT (c) 1989-2011.
9 *  On-Line Applications Research Corporation (OAR).
10 *
11 *  The license and distribution terms for this file may be
12 *  found in the file LICENSE in this distribution or at
13 *  http://www.rtems.com/license/LICENSE.
14 */
15
16#include <rtems.h>
17#include <bsp.h>
18#include <rtems/bspIo.h>
19#include <rtems/bspsmp.h>
20#include <stdlib.h>
21
22#define RTEMS_DEBUG
23
24static inline void sparc_leon3_set_cctrl( unsigned int val )
25{
26  __asm__ volatile( "sta %0, [%%g0] 2" : : "r" (val) );
27}
28
29static inline unsigned int sparc_leon3_get_cctrl( void )
30{
31  unsigned int v = 0;
32  __asm__ volatile( "lda [%%g0] 2, %0" : "=r" (v) : "0" (v) );
33  return v;
34}
35
36static rtems_isr bsp_ap_ipi_isr(
37  rtems_vector_number vector
38)
39{
40  LEON_Clear_interrupt(LEON3_MP_IRQ);
41  rtems_smp_process_interrupt();
42}
43
44static void leon3_secondary_cpu_initialize(void)
45{
46  int cpu = bsp_smp_processor_id();
47
48  sparc_leon3_set_cctrl( 0x80000F );
49  LEON_Unmask_interrupt(LEON3_MP_IRQ);
50  LEON3_IrqCtrl_Regs->mask[cpu] |= 1 << LEON3_MP_IRQ;
51
52  rtems_smp_secondary_cpu_initialize();
53}
54
55/*
56 *  Used to pass information to start.S when bringing secondary CPUs
57 *  out of reset.
58 */
59void *bsp_ap_stack;
60void *bsp_ap_entry;
61
62static void bsp_smp_delay( int );
63
64uint32_t bsp_smp_initialize( uint32_t configured_cpu_count )
65{
66  uint32_t cpu;
67  uint32_t found_cpus = 0;
68
69  sparc_leon3_set_cctrl( 0x80000F );
70  found_cpus =
71    ((LEON3_IrqCtrl_Regs->mpstat >> LEON3_IRQMPSTATUS_CPUNR) & 0xf)  + 1;
72  #if defined(RTEMS_DEBUG)
73    printk( "Found %d CPUs\n", found_cpus );
74  #endif
75
76  if ( found_cpus > configured_cpu_count ) {
77    printk(
78      "%d CPUs IS MORE THAN CONFIGURED -- ONLY USING %d\n",
79      found_cpus,
80      configured_cpu_count
81    );
82    found_cpus = configured_cpu_count;
83  }
84
85  if ( found_cpus == 1 )
86    return 1;
87
88  for ( cpu=1 ; cpu < found_cpus ; cpu++ ) {
89   
90    #if defined(RTEMS_DEBUG)
91      printk( "Waking CPU %d\n", cpu );
92    #endif
93
94    bsp_ap_stack = _Per_CPU_Information[cpu].interrupt_stack_high -
95                      CPU_MINIMUM_STACK_FRAME_SIZE;
96    bsp_ap_entry = leon3_secondary_cpu_initialize;
97
98    LEON3_IrqCtrl_Regs->mpstat = 1 << cpu;
99    bsp_smp_delay( 1000000 );
100    #if defined(RTEMS_DEBUG)
101      printk(
102        "CPU %d is %s\n",
103        cpu,
104        _Per_CPU_Information[cpu].state
105          == PER_CPU_STATE_READY_TO_BEGIN_MULTITASKING ?
106            "online" : "offline"
107      );
108    #endif
109  }
110
111  if ( found_cpus > 1 ) {
112    LEON_Unmask_interrupt(LEON3_MP_IRQ);
113    set_vector(bsp_ap_ipi_isr, LEON_TRAP_TYPE(LEON3_MP_IRQ), 1);
114  }
115  return found_cpus;
116}
117
118void bsp_smp_interrupt_cpu(
119  int cpu
120)
121{
122  /* send interrupt to destination CPU */
123  LEON3_IrqCtrl_Regs->force[cpu] = 1 << LEON3_MP_IRQ;
124}
125
126void bsp_smp_broadcast_interrupt(void)
127{
128  int dest_cpu;
129  int cpu;
130  int max_cpus;
131
132  cpu = bsp_smp_processor_id();
133  max_cpus = rtems_smp_get_number_of_processors();
134
135  for ( dest_cpu=0 ; dest_cpu < max_cpus ; dest_cpu++ ) {
136    if ( cpu == dest_cpu )
137      continue;
138    bsp_smp_interrupt_cpu( dest_cpu );
139    /* this is likely needed due to the ISR code not being SMP aware yet */
140    bsp_smp_delay( 100000 );
141  }
142}
143
144extern __inline__ void __delay(unsigned long loops)
145{
146   __asm__ __volatile__("cmp %0, 0\n\t"
147     "1: bne 1b\n\t"
148     "subcc %0, 1, %0\n" :
149     "=&r" (loops) :
150     "0" (loops) :
151     "cc"
152  );
153}
154
155/*
156 *  Kill time without depending on the timer being present or programmed.
157 *
158 *  This is not very sophisticated.
159 */
160void bsp_smp_delay( int max )
161{
162   __delay( max );
163}
Note: See TracBrowser for help on using the repository browser.