2 * Copyright (c) 2009 The Regents of the University of California
3 * Barret Rhoden <brho@cs.berkeley.edu>
4 * See LICENSE for details.
11 #include <arch/arch.h>
24 /* Lookup table for core_id and per_cpu_inf, indexed by real __core_id() */
25 int hw_coreid_lookup[MAX_NUM_CPUS] = {[0 ... (MAX_NUM_CPUS - 1)] -1};
26 int os_coreid_lookup[MAX_NUM_CPUS] = {[0 ... (MAX_NUM_CPUS - 1)] -1};
28 /*************************** IPI Wrapper Stuff ********************************/
29 // checklists to protect the global interrupt_handlers for 0xf0, f1, f2, f3, f4
30 // need to be global, since there is no function that will always exist for them
31 handler_wrapper_t (RO handler_wrappers)[NUM_HANDLER_WRAPPERS];
33 static int smp_call_function(uint8_t type, uint32_t dest, isr_t handler,
34 void *data, handler_wrapper_t **wait_wrapper)
38 handler_wrapper_t* wrapper;
39 extern atomic_t outstanding_calls;
41 // prevents us from ever having more than NUM_HANDLER_WRAPPERS callers in
42 // the process of competing for vectors. not decremented until both after
43 // the while(1) loop and after it's been waited on.
44 atomic_inc(&outstanding_calls);
45 if (atomic_read(&outstanding_calls) > NUM_HANDLER_WRAPPERS) {
46 atomic_dec(&outstanding_calls);
50 // assumes our cores are numbered in order
51 if ((type == 4) && (dest >= num_cpus))
52 panic("Destination CPU %d does not exist!", dest);
54 // build the mask based on the type and destination
55 INIT_CHECKLIST_MASK(cpu_mask, MAX_NUM_CPUS);
56 // set checklist mask's size dynamically to the num cpus actually present
57 cpu_mask.size = num_cpus;
60 SET_BITMASK_BIT(cpu_mask.bits, core_id());
63 FILL_BITMASK(cpu_mask.bits, num_cpus);
65 case 3: // all but self
66 FILL_BITMASK(cpu_mask.bits, num_cpus);
67 CLR_BITMASK_BIT(cpu_mask.bits, core_id());
69 case 4: // physical mode
70 // note this only supports sending to one specific physical id
71 // (only sets one bit, so if multiple cores have the same phys id
72 // the first one through will set this).
73 SET_BITMASK_BIT(cpu_mask.bits, dest);
75 case 5: // logical mode
77 warn("Logical mode bitmask handler protection not implemented!");
80 panic("Invalid type for cross-core function call!");
83 // Find an available vector/wrapper. Starts with this core's id (mod the
84 // number of wrappers). Walk through on conflict.
85 // Commit returns an error if it wanted to give up for some reason,
86 // like taking too long to acquire the lock or clear the mask, at which
87 // point, we try the next one.
88 // When we are done, wrapper points to the one we finally got.
89 // this wrapper_num trick doesn't work as well if you send a bunch in a row
90 // and wait, since you always check your main one (which is currently busy).
91 wrapper_num = core_id() % NUM_HANDLER_WRAPPERS;
93 wrapper = &handler_wrappers[wrapper_num];
94 if (!commit_checklist_wait(wrapper->cpu_list, &cpu_mask))
96 wrapper_num = (wrapper_num + 1) % NUM_HANDLER_WRAPPERS;
99 // instead of deadlock, smp_call can fail with this. makes it harder
100 // to use (have to check your return value). consider putting a delay
101 // here too (like if wrapper_num == initial_wrapper_num)
102 if (count++ > NUM_HANDLER_WRAPPERS * 1000) // note 1000 isn't enough...
107 // Wanting to wait is expressed by having a non-NULL handler_wrapper_t**
108 // passed in. Pass out our reference to wrapper, to wait later.
109 // If we don't want to wait, release the checklist (though it is still not
110 // clear, so it can't be used til everyone checks in).
112 *wait_wrapper = wrapper;
114 release_checklist(wrapper->cpu_list);
115 atomic_dec(&outstanding_calls);
118 /* TODO: once we can unregister, we can reregister. This here assumes that
119 * there is only one IRQ registered, and its the one for SMP call function.
120 * We're waiting on RCU to do a nice unregister. */
121 extern struct irq_handler *irq_handlers[];
122 if (!irq_handlers[wrapper->vector]) {
123 register_irq(wrapper->vector, handler, data, MKBUS(BusIPI, 0, 0, 0));
125 /* we're replacing the old one. hope it was ours, and the IRQ is firing
126 * concurrently (if it is, there's an smp_call bug)! */
127 irq_handlers[wrapper->vector]->isr = handler;
128 irq_handlers[wrapper->vector]->data = data;
131 // WRITE MEMORY BARRIER HERE
132 enable_irqsave(&state);
133 // Send the proper type of IPI. I made up these numbers.
136 send_self_ipi(wrapper->vector);
139 send_broadcast_ipi(wrapper->vector);
142 send_all_others_ipi(wrapper->vector);
144 case 4: // physical mode
145 send_ipi(dest, wrapper->vector);
147 case 5: // logical mode
148 send_group_ipi(dest, wrapper->vector);
151 panic("Invalid type for cross-core function call!");
153 // wait long enough to receive our own broadcast (PROBABLY WORKS) TODO
154 lapic_wait_to_send();
155 disable_irqsave(&state);
159 // Wrapper functions. Add more as they are needed.
160 int smp_call_function_self(isr_t handler, void *data,
161 handler_wrapper_t **wait_wrapper)
163 return smp_call_function(1, 0, handler, data, wait_wrapper);
166 int smp_call_function_all(isr_t handler, void *data,
167 handler_wrapper_t **wait_wrapper)
169 return smp_call_function(2, 0, handler, data, wait_wrapper);
172 int smp_call_function_single(uint32_t dest, isr_t handler, void *data,
173 handler_wrapper_t **wait_wrapper)
175 return smp_call_function(4, dest, handler, data, wait_wrapper);
178 // If you want to wait, pass the address of a pointer up above, then call
179 // this to do the actual waiting. Be somewhat careful about uninitialized
180 // or old wrapper pointers.
181 int smp_call_wait(handler_wrapper_t* wrapper)
184 waiton_checklist(wrapper->cpu_list);
187 warn("Attempting to wait on null wrapper! Check your return values!");