2018-01-30 01:23:49 +08:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2018 Intel corporation
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <kernel.h>
|
|
|
|
#include <kernel_structs.h>
|
|
|
|
#include <spinlock.h>
|
2018-01-18 03:34:50 +08:00
|
|
|
#include <kswap.h>
|
2018-02-09 01:10:46 +08:00
|
|
|
#include <kernel_internal.h>
|
2018-01-30 01:23:49 +08:00
|
|
|
|
|
|
|
static struct k_spinlock global_spinlock;
|
|
|
|
|
|
|
|
static volatile int recursive_count;
|
|
|
|
|
|
|
|
/* FIXME: this value of key works on all known architectures as an
|
|
|
|
* "invalid state" that will never be legitimately returned from
|
|
|
|
* _arch_irq_lock(). But we should force the architecture code to
|
|
|
|
* define something for us.
|
|
|
|
*/
|
|
|
|
#define KEY_RECURSIVE 0xffffffff
|
|
|
|
|
|
|
|
unsigned int _smp_global_lock(void)
|
|
|
|
{
|
|
|
|
/* OK to test this outside the lock. If it's non-zero, then
|
|
|
|
* we hold the lock by definition
|
|
|
|
*/
|
|
|
|
if (recursive_count) {
|
|
|
|
recursive_count++;
|
|
|
|
|
|
|
|
return KEY_RECURSIVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int k = k_spin_lock(&global_spinlock).key;
|
|
|
|
|
|
|
|
recursive_count = 1;
|
|
|
|
return k;
|
|
|
|
}
|
|
|
|
|
|
|
|
void _smp_global_unlock(unsigned int key)
|
|
|
|
{
|
|
|
|
if (key == KEY_RECURSIVE) {
|
|
|
|
recursive_count--;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
k_spinlock_key_t sk = { .key = key };
|
|
|
|
|
|
|
|
recursive_count = 0;
|
|
|
|
k_spin_unlock(&global_spinlock, sk);
|
|
|
|
}
|
2018-01-18 03:34:50 +08:00
|
|
|
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2018-01-27 04:30:21 +08:00
|
|
|
int k = irq_lock();
|
2018-01-18 03:34:50 +08:00
|
|
|
_arch_curr_cpu()->current = &dummy_thread;
|
2018-01-27 04:30:21 +08:00
|
|
|
smp_timer_init();
|
|
|
|
_Swap(k);
|
2018-01-18 03:34:50 +08:00
|
|
|
|
|
|
|
CODE_UNREACHABLE;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void smp_init(void)
|
|
|
|
{
|
|
|
|
atomic_t start_flag;
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
atomic_set(&start_flag, 1);
|
|
|
|
}
|