[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 |
---|
[c499856] | 14 | * http://www.rtems.org/license/LICENSE. |
---|
[06dcaf0] | 15 | */ |
---|
| 16 | |
---|
| 17 | #if HAVE_CONFIG_H |
---|
| 18 | #include "config.h" |
---|
| 19 | #endif |
---|
| 20 | |
---|
[6ca4f6a] | 21 | #include <rtems/score/smpimpl.h> |
---|
[f8ff2a0] | 22 | #include <rtems/score/assert.h> |
---|
[c5831a3f] | 23 | #include <rtems/score/schedulerimpl.h> |
---|
[4fc370e] | 24 | #include <rtems/score/threaddispatch.h> |
---|
[b4b309c] | 25 | #include <rtems/score/threadimpl.h> |
---|
[8a6de83] | 26 | #include <rtems/config.h> |
---|
[06dcaf0] | 27 | |
---|
[c5831a3f] | 28 | static void _SMP_Start_processors( uint32_t cpu_count ) |
---|
| 29 | { |
---|
[3380ee8] | 30 | uint32_t cpu_index_self = _SMP_Get_current_processor(); |
---|
[c5831a3f] | 31 | uint32_t cpu_index; |
---|
| 32 | |
---|
| 33 | |
---|
| 34 | for ( cpu_index = 0 ; cpu_index < cpu_count; ++cpu_index ) { |
---|
| 35 | const Scheduler_Assignment *assignment = |
---|
| 36 | _Scheduler_Get_assignment( cpu_index ); |
---|
[3380ee8] | 37 | Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); |
---|
[c5831a3f] | 38 | bool started; |
---|
| 39 | |
---|
[3380ee8] | 40 | if ( cpu_index != cpu_index_self ) { |
---|
[c5831a3f] | 41 | if ( _Scheduler_Should_start_processor( assignment ) ) { |
---|
| 42 | started = _CPU_SMP_Start_processor( cpu_index ); |
---|
| 43 | |
---|
| 44 | if ( !started && _Scheduler_Is_mandatory_processor( assignment ) ) { |
---|
| 45 | _SMP_Fatal( SMP_FATAL_START_OF_MANDATORY_PROCESSOR_FAILED ); |
---|
| 46 | } |
---|
| 47 | } else { |
---|
| 48 | started = false; |
---|
| 49 | } |
---|
| 50 | } else { |
---|
| 51 | started = true; |
---|
| 52 | |
---|
| 53 | if ( !_Scheduler_Should_start_processor( assignment ) ) { |
---|
| 54 | _SMP_Fatal( SMP_FATAL_BOOT_PROCESSOR_NOT_ASSIGNED_TO_SCHEDULER ); |
---|
| 55 | } |
---|
| 56 | } |
---|
| 57 | |
---|
[3380ee8] | 58 | cpu->started = started; |
---|
[c5831a3f] | 59 | |
---|
| 60 | if ( started ) { |
---|
[2369b10] | 61 | Scheduler_Context *context = |
---|
| 62 | _Scheduler_Get_context( assignment->scheduler ); |
---|
[38b59a6] | 63 | |
---|
[2369b10] | 64 | ++context->processor_count; |
---|
| 65 | cpu->scheduler_context = context; |
---|
[c5831a3f] | 66 | } |
---|
| 67 | } |
---|
| 68 | } |
---|
| 69 | |
---|
[282bfd3] | 70 | void _SMP_Handler_initialize( void ) |
---|
| 71 | { |
---|
[53e008b] | 72 | uint32_t cpu_max = rtems_configuration_get_maximum_processors(); |
---|
| 73 | uint32_t cpu_count; |
---|
| 74 | uint32_t cpu_index; |
---|
[282bfd3] | 75 | |
---|
[53e008b] | 76 | for ( cpu_index = 0 ; cpu_index < cpu_max; ++cpu_index ) { |
---|
[3380ee8] | 77 | Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); |
---|
[b1d08a58] | 78 | |
---|
[3380ee8] | 79 | _SMP_ticket_lock_Initialize( &cpu->Lock, "per-CPU" ); |
---|
[b1d08a58] | 80 | } |
---|
| 81 | |
---|
[282bfd3] | 82 | /* |
---|
| 83 | * Discover and initialize the secondary cores in an SMP system. |
---|
| 84 | */ |
---|
| 85 | |
---|
[53e008b] | 86 | cpu_count = _CPU_SMP_Initialize(); |
---|
| 87 | cpu_count = cpu_count < cpu_max ? cpu_count : cpu_max; |
---|
| 88 | _SMP_Processor_count = cpu_count; |
---|
| 89 | |
---|
[c5831a3f] | 90 | for ( cpu_index = cpu_count ; cpu_index < cpu_max; ++cpu_index ) { |
---|
| 91 | const Scheduler_Assignment *assignment = |
---|
| 92 | _Scheduler_Get_assignment( cpu_index ); |
---|
[53e008b] | 93 | |
---|
[c5831a3f] | 94 | if ( _Scheduler_Is_mandatory_processor( assignment ) ) { |
---|
| 95 | _SMP_Fatal( SMP_FATAL_MANDATORY_PROCESSOR_NOT_PRESENT ); |
---|
[53e008b] | 96 | } |
---|
| 97 | } |
---|
| 98 | |
---|
[c5831a3f] | 99 | _SMP_Start_processors( cpu_count ); |
---|
| 100 | |
---|
[53e008b] | 101 | _CPU_SMP_Finalize_initialization( cpu_count ); |
---|
[282bfd3] | 102 | } |
---|
| 103 | |
---|
[7336be9d] | 104 | void _SMP_Request_start_multitasking( void ) |
---|
[06dcaf0] | 105 | { |
---|
[fe52e7c0] | 106 | Per_CPU_Control *self_cpu = _Per_CPU_Get(); |
---|
[3380ee8] | 107 | uint32_t cpu_count = _SMP_Get_processor_count(); |
---|
| 108 | uint32_t cpu_index; |
---|
[7336be9d] | 109 | |
---|
| 110 | _Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING ); |
---|
[2f6108f9] | 111 | |
---|
[3380ee8] | 112 | for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) { |
---|
| 113 | Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); |
---|
[7336be9d] | 114 | |
---|
[6c36946f] | 115 | if ( _Per_CPU_Is_processor_started( cpu ) ) { |
---|
| 116 | _Per_CPU_State_change( cpu, PER_CPU_STATE_REQUEST_START_MULTITASKING ); |
---|
| 117 | } |
---|
[7336be9d] | 118 | } |
---|
| 119 | } |
---|
[2f6108f9] | 120 | |
---|
[7336be9d] | 121 | void _SMP_Start_multitasking_on_secondary_processor( void ) |
---|
| 122 | { |
---|
| 123 | Per_CPU_Control *self_cpu = _Per_CPU_Get(); |
---|
[d134adeb] | 124 | uint32_t cpu_index_self = _Per_CPU_Get_index( self_cpu ); |
---|
| 125 | const Scheduler_Assignment *assignment = |
---|
| 126 | _Scheduler_Get_assignment( cpu_index_self ); |
---|
[2f6108f9] | 127 | |
---|
[d134adeb] | 128 | if ( cpu_index_self >= rtems_configuration_get_maximum_processors() ) { |
---|
| 129 | _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_INVALID_PROCESSOR ); |
---|
| 130 | } |
---|
| 131 | |
---|
| 132 | if ( !_Scheduler_Should_start_processor( assignment ) ) { |
---|
[c5831a3f] | 133 | _SMP_Fatal( SMP_FATAL_MULTITASKING_START_ON_UNASSIGNED_PROCESSOR ); |
---|
| 134 | } |
---|
| 135 | |
---|
[7336be9d] | 136 | _Per_CPU_State_change( self_cpu, PER_CPU_STATE_READY_TO_START_MULTITASKING ); |
---|
[dad36c52] | 137 | |
---|
[514705d] | 138 | _Thread_Start_multitasking(); |
---|
[06dcaf0] | 139 | } |
---|
| 140 | |
---|
[7336be9d] | 141 | void _SMP_Request_shutdown( void ) |
---|
| 142 | { |
---|
[d50acdbb] | 143 | Per_CPU_Control *self_cpu = _Per_CPU_Get(); |
---|
[7336be9d] | 144 | |
---|
| 145 | _Per_CPU_State_change( self_cpu, PER_CPU_STATE_SHUTDOWN ); |
---|
[ba25cc2] | 146 | |
---|
| 147 | /* |
---|
| 148 | * We have to drop the Giant lock here in order to give other processors the |
---|
| 149 | * opportunity to receive the inter-processor interrupts issued previously. |
---|
| 150 | * In case the executing thread still holds SMP locks, then other processors |
---|
| 151 | * already waiting for this SMP lock will spin forever. |
---|
| 152 | */ |
---|
[d50acdbb] | 153 | _Giant_Drop( self_cpu ); |
---|
[7336be9d] | 154 | } |
---|
| 155 | |
---|
[4d906bda] | 156 | void _SMP_Send_message( uint32_t cpu_index, unsigned long message ) |
---|
[06dcaf0] | 157 | { |
---|
[3380ee8] | 158 | Per_CPU_Control *cpu = _Per_CPU_Get_by_index( cpu_index ); |
---|
[06dcaf0] | 159 | |
---|
[4d906bda] | 160 | _Atomic_Fetch_or_ulong( &cpu->message, message, ATOMIC_ORDER_RELAXED ); |
---|
[2f6108f9] | 161 | |
---|
[3380ee8] | 162 | _CPU_SMP_Send_interrupt( cpu_index ); |
---|
[06dcaf0] | 163 | } |
---|
| 164 | |
---|
[2f6108f9] | 165 | void _SMP_Broadcast_message( uint32_t message ) |
---|
[06dcaf0] | 166 | { |
---|
[3380ee8] | 167 | uint32_t cpu_count = _SMP_Get_processor_count(); |
---|
| 168 | uint32_t cpu_index_self = _SMP_Get_current_processor(); |
---|
| 169 | uint32_t cpu_index; |
---|
[2f6108f9] | 170 | |
---|
[ff25926] | 171 | _Assert( _Debug_Is_thread_dispatching_allowed() ); |
---|
[f8ff2a0] | 172 | |
---|
[3380ee8] | 173 | for ( cpu_index = 0 ; cpu_index < cpu_count ; ++cpu_index ) { |
---|
| 174 | if ( cpu_index != cpu_index_self ) { |
---|
| 175 | _SMP_Send_message( cpu_index, message ); |
---|
[2f6108f9] | 176 | } |
---|
[06dcaf0] | 177 | } |
---|
| 178 | } |
---|
[145becf] | 179 | |
---|
[58444f7] | 180 | SMP_Test_message_handler _SMP_Test_message_handler; |
---|