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