forked from zephyrproject-rtos/zephyr
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsmp.c
131 lines (106 loc) · 2.6 KB
/
smp.c
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
/* Copyright (c) 2022 Intel corporation
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/kernel.h>
#include <zephyr/kernel_structs.h>
#include <zephyr/spinlock.h>
#include <kswap.h>
#include <kernel_internal.h>
static atomic_t global_lock;
static atomic_t start_flag;
static atomic_t ready_flag;
unsigned int z_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 z_smp_global_unlock(unsigned int key)
{
if (_current->base.global_lock_count != 0U) {
_current->base.global_lock_count--;
if (!_current->base.global_lock_count) {
atomic_clear(&global_lock);
}
}
arch_irq_unlock(key);
}
/* Called from within z_swap(), so assumes lock already held */
void z_smp_release_global_lock(struct k_thread *thread)
{
if (!thread->base.global_lock_count) {
atomic_clear(&global_lock);
}
}
/* Tiny delay that relaxes bus traffic to avoid spamming a shared
* memory bus looking at an atomic variable
*/
static inline void local_delay(void)
{
for (volatile int i = 0; i < 1000; i++) {
}
}
static void wait_for_start_signal(atomic_t *cpu_start_flag)
{
/* Wait for the signal to begin scheduling */
while (!atomic_get(cpu_start_flag)) {
local_delay();
}
}
/* Legacy interfaces for early-version SOF CPU bringup. To be removed */
#ifdef CONFIG_SOF
void z_smp_thread_init(void *arg, struct k_thread *thread)
{
z_dummy_thread_init(thread);
wait_for_start_signal(arg);
}
void z_smp_thread_swap(void)
{
z_swap_unlocked();
}
#endif
static inline FUNC_NORETURN void smp_init_top(void *arg)
{
struct k_thread dummy_thread;
(void)atomic_set(&ready_flag, 1);
wait_for_start_signal(arg);
z_dummy_thread_init(&dummy_thread);
smp_timer_init();
z_swap_unlocked();
CODE_UNREACHABLE; /* LCOV_EXCL_LINE */
}
static void start_cpu(int id, atomic_t *start_flag)
{
z_init_cpu(id);
(void)atomic_clear(&ready_flag);
arch_start_cpu(id, z_interrupt_stacks[id], CONFIG_ISR_STACK_SIZE,
smp_init_top, start_flag);
while (!atomic_get(&ready_flag)) {
local_delay();
}
}
void z_smp_start_cpu(int id)
{
(void)atomic_set(&start_flag, 1); /* async, don't care */
start_cpu(id, &start_flag);
}
void z_smp_init(void)
{
(void)atomic_clear(&start_flag);
unsigned int num_cpus = arch_num_cpus();
for (int i = 1; i < num_cpus; i++) {
start_cpu(i, &start_flag);
}
(void)atomic_set(&start_flag, 1);
}
bool z_smp_cpu_mobile(void)
{
unsigned int k = arch_irq_lock();
bool pinned = arch_is_in_isr() || !arch_irq_unlocked(k);
arch_irq_unlock(k);
return !pinned;
}