| /* |
| * 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) |
| { |
| 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; |
| int k = irq_lock(); |
| smp_timer_init(); |
| _Swap(k); |
| |
| 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); |
| } |