tests/linux: use Akaros's CFLAGS
[akaros.git] / kern / arch / riscv / smp.c
1 #include <arch/arch.h>
2 #include <arch/smp.h>
3 #include <assert.h>
4 #include <atomic.h>
5 #include <error.h>
6 #include <pmap.h>
7 #include <smp.h>
8 #include <stdio.h>
9 #include <string.h>
10
11 volatile uint32_t num_cores_booted = 0;
12
13 void smp_boot(void)
14 {
15         smp_percpu_init();
16         num_cores_booted = 1;
17         while (num_cores_booted < num_cores)
18                 ;
19         printd("%d cores reporting!\n", num_cores);
20 }
21
22 void smp_init(void)
23 {
24         smp_percpu_init();
25
26         __sync_fetch_and_add(&num_cores_booted, 1);
27         printd("Good morning, Vietnam! (core id = %d)\n", core_id());
28
29         smp_idle();
30 }
31
32 handler_wrapper_t *smp_make_wrapper(void)
33 {
34         static handler_wrapper_t wrapper_pool[MAX_NUM_CORES * 8] = {
35             {{0}, SPINLOCK_INITIALIZER}};
36
37         size_t i;
38         for (i = 0; i < sizeof(wrapper_pool) / sizeof(wrapper_pool[0]); i++)
39                 if (spin_trylock(&wrapper_pool[i].lock) == 0)
40                         return &wrapper_pool[i];
41         return NULL;
42 }
43
44 void smp_call_wrapper(uint32_t src, isr_t handler, handler_wrapper_t *wrapper,
45                       void *data)
46 {
47         if (wrapper)
48                 wrapper->wait_list[core_id()] = 0;
49         handler(0, data);
50 }
51
52 int smp_call_function_self(isr_t handler, void *data,
53                            handler_wrapper_t **wait_wrapper)
54 {
55         return smp_call_function_single(core_id(), handler, data, wait_wrapper);
56 }
57
58 int smp_call_function_all(isr_t handler, void *data,
59                           handler_wrapper_t **wait_wrapper)
60 {
61         int8_t state = 0;
62         int i, me;
63         handler_wrapper_t *wrapper = 0;
64
65         if (wait_wrapper) {
66                 wrapper = *wait_wrapper = smp_make_wrapper();
67                 if (!wrapper)
68                         return -ENOMEM;
69
70                 for (i = 0; i < num_cores; i++)
71                         wrapper->wait_list[i] = 1;
72         }
73
74         enable_irqsave(&state);
75
76         // send to others
77         for (i = 0, me = core_id(); i < num_cores; i++) {
78                 if (i == me)
79                         continue;
80
81                 send_kernel_message(i, (amr_t)smp_call_wrapper, (long)handler,
82                                     (long)wrapper, (long)data, KMSG_IMMEDIATE);
83         }
84
85         // send to me
86         send_kernel_message(me, (amr_t)smp_call_wrapper, (long)handler,
87                             (long)wrapper, (long)data, KMSG_IMMEDIATE);
88
89         cpu_relax(); // wait to get the interrupt
90
91         disable_irqsave(&state);
92
93         return 0;
94 }
95
96 int smp_call_function_single(uint32_t dest, isr_t handler, void *data,
97                              handler_wrapper_t **wait_wrapper)
98 {
99         int8_t state = 0;
100         handler_wrapper_t *wrapper = 0;
101
102         if (wait_wrapper) {
103                 wrapper = *wait_wrapper = smp_make_wrapper();
104                 if (!wrapper)
105                         return -ENOMEM;
106                 wrapper->wait_list[dest] = 1;
107         }
108
109         enable_irqsave(&state);
110
111         send_kernel_message(dest, (amr_t)smp_call_wrapper, (long)handler,
112                             (long)wrapper, (long)data, KMSG_IMMEDIATE);
113
114         cpu_relax(); // wait to get the interrupt, if it's to this core
115
116         disable_irqsave(&state);
117
118         return 0;
119 }
120
121 int smp_call_wait(handler_wrapper_t *wrapper)
122 {
123         int i;
124
125         for (i = 0; i < num_cores; i++)
126                 while (wrapper->wait_list[i])
127                         ;
128
129         spin_unlock(&wrapper->lock);
130         return 0;
131 }
132
133 /* Perform any initialization needed by per_cpu_info.  Right now, this just
134  * inits the amsg list.  Make sure every core calls this at some point in the
135  * smp_boot process. */
136 void __arch_pcpu_init(uint32_t coreid)
137 {
138         // Switch to the real L1 page table, rather than the boot page table
139         // which has the [0,KERNSIZE-1] identity mapping.
140         extern pte_t l1pt[NPTENTRIES];
141         lcr3(PADDR(l1pt));
142
143         register uintptr_t sp asm("sp");
144         set_stack_top(ROUNDUP(sp, PGSIZE));
145 }