summaryrefslogtreecommitdiff
path: root/bsps/sparc/leon3/start/bspsmp.c
blob: 7f8496289a704f7444d45252286a027b76ca6311 (plain)
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
/**
 * @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.org/license/LICENSE.
 */

#include <bsp.h>
#include <bsp/bootcard.h>
#include <bsp/fatal.h>
#include <bsp/irq.h>
#include <bsp/leon3.h>
#include <rtems/bspIo.h>
#include <rtems/sysinit.h>
#include <rtems/score/assert.h>
#include <rtems/score/smpimpl.h>
#include <stdlib.h>

#if !defined(__leon__) || defined(RTEMS_PARAVIRT)
uint32_t _CPU_SMP_Get_current_processor( void )
{
  return _LEON3_Get_current_processor();
}
#endif

static void bsp_inter_processor_interrupt( void *arg )
{
  (void) arg;
  _SMP_Inter_processor_interrupt_handler(_Per_CPU_Get());
}

void bsp_start_on_secondary_processor(Per_CPU_Control *cpu_self)
{
  /*
   * If data cache snooping is not enabled we terminate using BSP_fatal_exit()
   * instead of bsp_fatal().  This is done since the latter function tries to
   * acquire a ticket lock, an operation which requires data cache snooping to
   * be enabled.
   */
  if ( !leon3_data_cache_snooping_enabled() )
    BSP_fatal_exit( LEON3_FATAL_INVALID_CACHE_CONFIG_SECONDARY_PROCESSOR );

  _SMP_Start_multitasking_on_secondary_processor(cpu_self);
}

static rtems_interrupt_entry leon3_inter_processor_interrupt_entry =
  RTEMS_INTERRUPT_ENTRY_INITIALIZER(
    bsp_inter_processor_interrupt,
    NULL,
    "IPI"
  );

static void leon3_install_inter_processor_interrupt( void )
{
  rtems_status_code sc;
  rtems_vector_number irq;

  irq = LEON3_mp_irq;

  bsp_interrupt_set_affinity( irq, _SMP_Get_online_processors() );

  sc = rtems_interrupt_entry_install(
    irq,
    RTEMS_INTERRUPT_SHARED,
    &leon3_inter_processor_interrupt_entry
  );
  _Assert_Unused_variable_equals( sc, RTEMS_SUCCESSFUL );
}

static uint32_t leon3_get_cpu_count( const irqamp *regs )
{
  return IRQAMP_MPSTAT_NCPU_GET( grlib_load_32( &regs->mpstat ) ) + 1;
}

uint32_t _CPU_SMP_Initialize( void )
{
  if ( !leon3_data_cache_snooping_enabled() )
    bsp_fatal( LEON3_FATAL_INVALID_CACHE_CONFIG_BOOT_PROCESSOR );

  return leon3_get_cpu_count(LEON3_IrqCtrl_Regs);
}

bool _CPU_SMP_Start_processor( uint32_t cpu_index )
{
  #if defined(RTEMS_DEBUG)
    printk( "Waking CPU %d\n", cpu_index );
  #endif

  grlib_store_32(
    &LEON3_IrqCtrl_Regs->mpstat,
    IRQAMP_MPSTAT_STATUS(1U << cpu_index)
  );

  return true;
}

void _CPU_SMP_Finalize_initialization( uint32_t cpu_count )
{
  (void) cpu_count;

#if !defined(RTEMS_DRVMGR_STARTUP)
  leon3_install_inter_processor_interrupt();
#endif
}

void _CPU_SMP_Prepare_start_multitasking( void )
{
  /* Do nothing */
}

void _CPU_SMP_Send_interrupt(uint32_t target_processor_index)
{
  /* send interrupt to destination CPU */
  grlib_store_32(
    &LEON3_IrqCtrl_Regs->piforce[target_processor_index],
    1U << LEON3_mp_irq
  );
}

#if defined(RTEMS_DRVMGR_STARTUP)
RTEMS_SYSINIT_ITEM(
  leon3_install_inter_processor_interrupt,
  RTEMS_SYSINIT_DRVMGR_LEVEL_1,
  RTEMS_SYSINIT_ORDER_LAST_BUT_4
);
#endif