You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
2.3 KiB
117 lines
2.3 KiB
/* |
|
* Copyright (c) 2018 Intel corporation |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
|
|
#include <kernel.h> |
|
#include <kernel_structs.h> |
|
#include <spinlock.h> |
|
#include <kswap.h> |
|
#include <kernel_internal.h> |
|
|
|
#ifdef CONFIG_SMP |
|
static atomic_t global_lock; |
|
|
|
unsigned int _smp_global_lock(void) |
|
{ |
|
unsigned int key = _arch_irq_lock(); |
|
|
|
if (!_current->base.global_lock_count) { |
|
while (!atomic_cas(&global_lock, 0, 1)) { |
|
} |
|
} |
|
|
|
_current->base.global_lock_count++; |
|
|
|
return key; |
|
} |
|
|
|
void _smp_global_unlock(unsigned int key) |
|
{ |
|
if (_current->base.global_lock_count) { |
|
_current->base.global_lock_count--; |
|
|
|
if (!_current->base.global_lock_count) { |
|
atomic_clear(&global_lock); |
|
} |
|
} |
|
|
|
_arch_irq_unlock(key); |
|
} |
|
|
|
void _smp_reacquire_global_lock(struct k_thread *thread) |
|
{ |
|
if (thread->base.global_lock_count) { |
|
_arch_irq_lock(); |
|
|
|
while (!atomic_cas(&global_lock, 0, 1)) { |
|
} |
|
} |
|
} |
|
|
|
|
|
/* Called from within _Swap(), so assumes lock already held */ |
|
void _smp_release_global_lock(struct k_thread *thread) |
|
{ |
|
if (!thread->base.global_lock_count) { |
|
atomic_clear(&global_lock); |
|
} |
|
} |
|
|
|
#endif |
|
|
|
extern k_thread_stack_t _interrupt_stack1[]; |
|
extern k_thread_stack_t _interrupt_stack2[]; |
|
extern k_thread_stack_t _interrupt_stack3[]; |
|
|
|
#ifdef CONFIG_SMP |
|
static void smp_init_top(int key, void *arg) |
|
{ |
|
atomic_t *start_flag = arg; |
|
|
|
/* Wait for the signal to begin scheduling */ |
|
do { |
|
k_busy_wait(100); |
|
} while (!atomic_get(start_flag)); |
|
|
|
/* Switch out of a dummy thread. Trick cribbed from the main |
|
* thread init. Should probably unify implementations. |
|
*/ |
|
struct k_thread dummy_thread = { |
|
.base.user_options = K_ESSENTIAL, |
|
.base.thread_state = _THREAD_DUMMY, |
|
}; |
|
|
|
_arch_curr_cpu()->current = &dummy_thread; |
|
unsigned int k = irq_lock(); |
|
smp_timer_init(); |
|
(void)_Swap(k); |
|
|
|
CODE_UNREACHABLE; |
|
} |
|
#endif |
|
|
|
void smp_init(void) |
|
{ |
|
atomic_t start_flag; |
|
|
|
(void)atomic_clear(&start_flag); |
|
|
|
#if defined(CONFIG_SMP) && CONFIG_MP_NUM_CPUS > 1 |
|
_arch_start_cpu(1, _interrupt_stack1, CONFIG_ISR_STACK_SIZE, |
|
smp_init_top, &start_flag); |
|
#endif |
|
|
|
#if defined(CONFIG_SMP) && CONFIG_MP_NUM_CPUS > 2 |
|
_arch_start_cpu(2, _interrupt_stack2, CONFIG_ISR_STACK_SIZE, |
|
smp_init_top, &start_flag); |
|
#endif |
|
|
|
#if defined(CONFIG_SMP) && CONFIG_MP_NUM_CPUS > 3 |
|
_arch_start_cpu(3, _interrupt_stack3, CONFIG_ISR_STACK_SIZE, |
|
smp_init_top, &start_flag); |
|
#endif |
|
|
|
(void)atomic_set(&start_flag, 1); |
|
}
|
|
|