kconfig: use pkg-config for ncurses detection
[akaros.git] / kern / arch / x86 / smp.c
1 /*
2  * Copyright (c) 2009 The Regents of the University of California
3  * Barret Rhoden <brho@cs.berkeley.edu>
4  * See LICENSE for details.
5  */
6
7 #include <arch/arch.h>
8 #include <arch/topology.h>
9 #include <bitmask.h>
10 #include <smp.h>
11
12 #include <atomic.h>
13 #include <error.h>
14 #include <stdio.h>
15 #include <string.h>
16 #include <assert.h>
17 #include <pmap.h>
18 #include <env.h>
19 #include <trap.h>
20
21 /*************************** IPI Wrapper Stuff ********************************/
22 // checklists to protect the global interrupt_handlers for 0xf0, f1, f2, f3, f4
23 // need to be global, since there is no function that will always exist for them
24 handler_wrapper_t handler_wrappers[NUM_HANDLER_WRAPPERS];
25
26 static int smp_call_function(uint8_t type, uint32_t dest, isr_t handler,
27                              void *data, handler_wrapper_t **wait_wrapper)
28 {
29         int8_t state = 0;
30         uint32_t wrapper_num;
31         handler_wrapper_t* wrapper;
32         extern atomic_t outstanding_calls;
33
34         // prevents us from ever having more than NUM_HANDLER_WRAPPERS callers
35         // in the process of competing for vectors.  not decremented until both
36         // after the while(1) loop and after it's been waited on.
37         atomic_inc(&outstanding_calls);
38         if (atomic_read(&outstanding_calls) > NUM_HANDLER_WRAPPERS) {
39                 atomic_dec(&outstanding_calls);
40                 return -EBUSY;
41         }
42
43         // assumes our cores are numbered in order
44         if ((type == 4) && (dest >= num_cores))
45                 panic("Destination CPU %d does not exist!", dest);
46
47         // build the mask based on the type and destination
48         INIT_CHECKLIST_MASK(cpu_mask, MAX_NUM_CORES);
49         // set checklist mask's size dynamically to the num cpus actually
50         // present
51         cpu_mask.size = num_cores;
52         switch (type) {
53         case 1: // self
54                 SET_BITMASK_BIT(cpu_mask.bits, core_id());
55                 break;
56         case 2: // all
57                 FILL_BITMASK(cpu_mask.bits, num_cores);
58                 break;
59         case 3: // all but self
60                 FILL_BITMASK(cpu_mask.bits, num_cores);
61                 CLR_BITMASK_BIT(cpu_mask.bits, core_id());
62                 break;
63         case 4: // physical mode
64                 // note this only supports sending to one specific physical id
65                 // (only sets one bit, so if multiple cores have the same phys
66                 // id the first one through will set this).
67                 SET_BITMASK_BIT(cpu_mask.bits, dest);
68                 break;
69         case 5: // logical mode
70                 // TODO
71                 warn("Logical mode bitmask handler protection unimplemented!");
72                 break;
73         default:
74                 panic("Invalid type for cross-core function call!");
75         }
76
77         // Find an available vector/wrapper.  Starts with this core's id (mod
78         // the number of wrappers).  Walk through on conflict.
79         // Commit returns an error if it wanted to give up for some reason,
80         // like taking too long to acquire the lock or clear the mask, at which
81         // point, we try the next one.
82         // When we are done, wrapper points to the one we finally got.
83         // this wrapper_num trick doesn't work as well if you send a bunch in a
84         // row and wait, since you always check your main one (which is
85         // currently busy).
86         wrapper_num = core_id() % NUM_HANDLER_WRAPPERS;
87         while(1) {
88                 wrapper = &handler_wrappers[wrapper_num];
89                 if (!commit_checklist_wait(wrapper->cpu_list, &cpu_mask))
90                         break;
91                 wrapper_num = (wrapper_num + 1) % NUM_HANDLER_WRAPPERS;
92                 /*
93                 uint32_t count = 0;
94                 // instead of deadlock, smp_call can fail with this.  makes it
95                 // harder to use (have to check your return value).  consider
96                 // putting a delay here too (like if wrapper_num ==
97                 // initial_wrapper_num)
98                 // note 1000 isn't enough...
99                 if (count++ > NUM_HANDLER_WRAPPERS * 1000)
100                         return -EBUSY;
101                 */
102         }
103
104         // Wanting to wait is expressed by having a non-NULL handler_wrapper_t**
105         // passed in.  Pass out our reference to wrapper, to wait later.  If we
106         // don't want to wait, release the checklist (though it is still not
107         // clear, so it can't be used til everyone checks in).
108         if (wait_wrapper)
109                 *wait_wrapper = wrapper;
110         else {
111                 release_checklist(wrapper->cpu_list);
112                 atomic_dec(&outstanding_calls);
113         }
114
115         /* TODO: once we can unregister, we can reregister.  This here assumes
116          * that there is only one IRQ registered, and its the one for SMP call
117          * function.  We're waiting on RCU to do a nice unregister. */
118         extern struct irq_handler *irq_handlers[];
119
120         if (!irq_handlers[wrapper->vector]) {
121                 register_irq(wrapper->vector, handler, data, MKBUS(BusIPI, 0, 0,
122                                                                    0));
123         } else {
124                 /* we're replacing the old one.  hope it was ours, and the IRQ
125                  * is firing concurrently (if it is, there's an smp_call bug)!
126                  * */
127                 irq_handlers[wrapper->vector]->isr = handler;
128                 irq_handlers[wrapper->vector]->data = data;
129         }
130
131         // WRITE MEMORY BARRIER HERE
132         enable_irqsave(&state);
133         // Send the proper type of IPI.  I made up these numbers.
134         switch (type) {
135         case 1:
136                 send_self_ipi(wrapper->vector);
137                 break;
138         case 2:
139                 send_broadcast_ipi(wrapper->vector);
140                 break;
141         case 3:
142                 send_all_others_ipi(wrapper->vector);
143                 break;
144         case 4: // physical mode
145                 send_ipi(dest, wrapper->vector);
146                 break;
147         case 5: // logical mode
148                 send_group_ipi(dest, wrapper->vector);
149                 break;
150         default:
151                 panic("Invalid type for cross-core function call!");
152         }
153         // wait long enough to receive our own broadcast (PROBABLY WORKS) TODO
154         disable_irqsave(&state);
155         return 0;
156 }
157
158 // Wrapper functions.  Add more as they are needed.
159 int smp_call_function_self(isr_t handler, void *data,
160                            handler_wrapper_t **wait_wrapper)
161 {
162         return smp_call_function(1, 0, handler, data, wait_wrapper);
163 }
164
165 int smp_call_function_all(isr_t handler, void *data,
166                           handler_wrapper_t **wait_wrapper)
167 {
168         return smp_call_function(2, 0, handler, data, wait_wrapper);
169 }
170
171 int smp_call_function_single(uint32_t dest, isr_t handler, void *data,
172                              handler_wrapper_t **wait_wrapper)
173 {
174         return smp_call_function(4, dest, handler, data, wait_wrapper);
175 }
176
177 // If you want to wait, pass the address of a pointer up above, then call
178 // this to do the actual waiting.  Be somewhat careful about uninitialized
179 // or old wrapper pointers.
180 int smp_call_wait(handler_wrapper_t* wrapper)
181 {
182         if (wrapper) {
183                 waiton_checklist(wrapper->cpu_list);
184                 return 0;
185         } else {
186                 warn("Attempting to wait on null wrapper!  Check your return values!");
187                 return -EFAIL;
188         }
189 }
190