Kernel uses ARCH_CL_SIZE (XCC)
[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
47 smp_call_wrapper(trapframe_t* tf, uint32_t src, isr_t handler,
48                  handler_wrapper_t* wrapper, void* data)
49 {
50         if(wrapper)
51                 wrapper->wait_list[core_id()] = 0;
52         handler(tf, data);
53 }
54
55 int smp_call_function_self(isr_t handler, void* data,
56                            handler_wrapper_t** wait_wrapper)
57 {
58         return smp_call_function_single(core_id(), handler, data, wait_wrapper);
59 }
60
61 int smp_call_function_all(isr_t handler, void* data,
62                           handler_wrapper_t** wait_wrapper)
63 {
64         int8_t state = 0;
65         int i, me;
66         handler_wrapper_t* wrapper = 0;
67         if(wait_wrapper)
68         {
69                 wrapper = *wait_wrapper = smp_make_wrapper();
70                 if(!wrapper)
71                         return -ENOMEM;
72
73                 for(i = 0; i < num_cpus; i++)
74                         wrapper->wait_list[i] = 1;
75         }
76
77         enable_irqsave(&state);
78
79         // send to others
80         for(i = 0, me = core_id(); i < num_cpus; i++)
81         {
82                 if(i == me)
83                         continue;
84
85                 send_kernel_message(i, (amr_t)smp_call_wrapper, (long)handler,
86                                     (long)wrapper, (long)data, KMSG_IMMEDIATE);
87         }
88
89         // send to me
90         send_kernel_message(me, (amr_t)smp_call_wrapper, (long)handler,
91                             (long)wrapper, (long)data, KMSG_IMMEDIATE);
92
93         cpu_relax(); // wait to get the interrupt
94
95         disable_irqsave(&state);
96
97         return 0;
98 }
99
100 int smp_call_function_single(uint32_t dest, isr_t handler, void* data,
101                              handler_wrapper_t** wait_wrapper)
102 {
103         int8_t state = 0;
104         handler_wrapper_t* wrapper = 0;
105         if(wait_wrapper)
106         {
107                 wrapper = *wait_wrapper = smp_make_wrapper();
108                 if(!wrapper)
109                         return -ENOMEM;
110                 wrapper->wait_list[dest] = 1;
111         }
112
113         enable_irqsave(&state);
114
115         send_kernel_message(dest, (amr_t)smp_call_wrapper, (long)handler,
116                             (long)wrapper, (long)data, KMSG_IMMEDIATE);
117
118         cpu_relax(); // wait to get the interrupt, if it's to this core
119
120         disable_irqsave(&state);
121
122         return 0;
123 }
124
125 int smp_call_wait(handler_wrapper_t* wrapper)
126 {
127         int i;
128         for(i = 0; i < num_cpus; i++)
129                 while(wrapper->wait_list[i]);
130
131         spin_unlock(&wrapper->lock);
132         return 0;
133 }
134
135 /* Perform any initialization needed by per_cpu_info.  Right now, this just
136  * inits the amsg list (which sparc will probably also want).  Make sure every
137  * core calls this at some point in the smp_boot process. */
138 void __arch_pcpu_init(uint32_t coreid)
139 {
140         // Switch to the real L1 page table, rather than the boot page table which
141         // has the [0,KERNSIZE-1] identity mapping.
142         extern pte_t l1pt[NPTENTRIES];
143         lcr3(PADDR(l1pt));
144
145         register uintptr_t sp asm ("sp");
146         set_stack_top(ROUNDUP(sp, PGSIZE));
147 }