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