summaryrefslogtreecommitdiffstats
path: root/c/src/lib/libbsp/sparc/leon3/smp/smp_leon3.c
blob: e62ddac23b946b5d3492da174e2f44392686bce3 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/**
 * @file
 * @ingroup sparc_leon3
 * @brief LEON3 SMP BSP Support
 */

/*
 *  COPYRIGHT (c) 1989-2011.
 *  On-Line Applications Research Corporation (OAR).
 *
 *  The license and distribution terms for this file may be
 *  found in the file LICENSE in this distribution or at
 *  http://www.rtems.com/license/LICENSE.
 */

#include <bsp.h>
#include <leon.h>
#include <rtems/bspIo.h>
#include <rtems/bspsmp.h>
#include <stdlib.h>

#define RTEMS_DEBUG

static inline void sparc_leon3_set_cctrl( unsigned int val )
{
  __asm__ volatile( "sta %0, [%%g0] 2" : : "r" (val) );
}

static inline unsigned int sparc_leon3_get_cctrl( void )
{
  unsigned int v = 0;
  __asm__ volatile( "lda [%%g0] 2, %0" : "=r" (v) : "0" (v) );
  return v;
}

static rtems_isr bsp_ap_ipi_isr(
  rtems_vector_number vector
)
{
  rtems_smp_process_interrupt();
}

void leon3_secondary_cpu_initialize(uint32_t cpu)
{
  sparc_leon3_set_cctrl( 0x80000F );
  LEON_Unmask_interrupt(LEON3_MP_IRQ);
  LEON3_IrqCtrl_Regs->mask[cpu] |= 1 << LEON3_MP_IRQ;

  rtems_smp_secondary_cpu_initialize();
}

static void bsp_smp_delay( int );

uint32_t bsp_smp_initialize( uint32_t configured_cpu_count )
{
  uint32_t cpu;
  uint32_t found_cpus = 0;

  sparc_leon3_set_cctrl( 0x80000F );
  found_cpus =
    ((LEON3_IrqCtrl_Regs->mpstat >> LEON3_IRQMPSTATUS_CPUNR) & 0xf)  + 1;

  #if defined(RTEMS_DEBUG)
    printk( "Found %d CPUs\n", found_cpus );

    if ( found_cpus > configured_cpu_count ) {
      printk(
        "%d CPUs IS MORE THAN CONFIGURED -- ONLY USING %d\n",
        found_cpus,
        configured_cpu_count
      );
      found_cpus = configured_cpu_count;
    }
  #endif

  if ( found_cpus > 1 ) {
    LEON_Unmask_interrupt(LEON3_MP_IRQ);
    set_vector(bsp_ap_ipi_isr, LEON_TRAP_TYPE(LEON3_MP_IRQ), 1);
  }

  for ( cpu = 1 ; cpu < found_cpus ; ++cpu ) {
    #if defined(RTEMS_DEBUG)
      printk( "Waking CPU %d\n", cpu );
    #endif

    LEON3_IrqCtrl_Regs->mpstat = 1 << cpu;
  }

  return found_cpus;
}

void _CPU_SMP_Send_interrupt(uint32_t target_processor_index)
{
  /* send interrupt to destination CPU */
  LEON3_IrqCtrl_Regs->force[target_processor_index] = 1 << LEON3_MP_IRQ;
}

void bsp_smp_broadcast_interrupt(void)
{
  uint32_t dest_cpu;
  uint32_t cpu;
  uint32_t max_cpus;

  cpu = rtems_smp_get_current_processor();
  max_cpus = rtems_smp_get_processor_count();

  for ( dest_cpu=0 ; dest_cpu < max_cpus ; dest_cpu++ ) {
    if ( cpu == dest_cpu )
      continue;
    _CPU_SMP_Send_interrupt( dest_cpu );
    /* this is likely needed due to the ISR code not being SMP aware yet */
    bsp_smp_delay( 100000 );
  }
}

static __inline__ void __delay(unsigned long loops)
{
   __asm__ __volatile__("cmp %0, 0\n\t"
     "1: bne 1b\n\t"
     "subcc %0, 1, %0\n" :
     "=&r" (loops) :
     "0" (loops) :
     "cc"
  );
}

/*
 *  Kill time without depending on the timer being present or programmed.
 *
 *  This is not very sophisticated.
 */
void bsp_smp_delay( int max )
{
   __delay( max );
}