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