blob: 2126bbf817474195b061f8cbfbbc37faebf1d178 [file] [log] [blame]
#include <arch/arch.h>
#include <arch/smp.h>
#include <assert.h>
#include <atomic.h>
#include <error.h>
#include <pmap.h>
#include <smp.h>
#include <stdio.h>
#include <string.h>
volatile uint32_t num_cores_booted = 0;
void smp_boot(void)
{
smp_percpu_init();
num_cores_booted = 1;
while (num_cores_booted < num_cores)
;
printd("%d cores reporting!\n", num_cores);
}
void smp_init(void)
{
smp_percpu_init();
__sync_fetch_and_add(&num_cores_booted, 1);
printd("Good morning, Vietnam! (core id = %d)\n", core_id());
smp_idle();
}
handler_wrapper_t *smp_make_wrapper(void)
{
static handler_wrapper_t wrapper_pool[MAX_NUM_CORES * 8] = {
{{0}, SPINLOCK_INITIALIZER}};
size_t i;
for (i = 0; i < sizeof(wrapper_pool) / sizeof(wrapper_pool[0]); i++)
if (spin_trylock(&wrapper_pool[i].lock) == 0)
return &wrapper_pool[i];
return NULL;
}
void smp_call_wrapper(uint32_t src, isr_t handler, handler_wrapper_t *wrapper,
void *data)
{
if (wrapper)
wrapper->wait_list[core_id()] = 0;
handler(0, data);
}
int smp_call_function_self(isr_t handler, void *data,
handler_wrapper_t **wait_wrapper)
{
return smp_call_function_single(core_id(), handler, data, wait_wrapper);
}
int smp_call_function_all(isr_t handler, void *data,
handler_wrapper_t **wait_wrapper)
{
int8_t state = 0;
int i, me;
handler_wrapper_t *wrapper = 0;
if (wait_wrapper) {
wrapper = *wait_wrapper = smp_make_wrapper();
if (!wrapper)
return -ENOMEM;
for (i = 0; i < num_cores; i++)
wrapper->wait_list[i] = 1;
}
enable_irqsave(&state);
// send to others
for (i = 0, me = core_id(); i < num_cores; i++) {
if (i == me)
continue;
send_kernel_message(i, (amr_t)smp_call_wrapper, (long)handler,
(long)wrapper, (long)data, KMSG_IMMEDIATE);
}
// send to me
send_kernel_message(me, (amr_t)smp_call_wrapper, (long)handler,
(long)wrapper, (long)data, KMSG_IMMEDIATE);
cpu_relax(); // wait to get the interrupt
disable_irqsave(&state);
return 0;
}
int smp_call_function_single(uint32_t dest, isr_t handler, void *data,
handler_wrapper_t **wait_wrapper)
{
int8_t state = 0;
handler_wrapper_t *wrapper = 0;
if (wait_wrapper) {
wrapper = *wait_wrapper = smp_make_wrapper();
if (!wrapper)
return -ENOMEM;
wrapper->wait_list[dest] = 1;
}
enable_irqsave(&state);
send_kernel_message(dest, (amr_t)smp_call_wrapper, (long)handler,
(long)wrapper, (long)data, KMSG_IMMEDIATE);
cpu_relax(); // wait to get the interrupt, if it's to this core
disable_irqsave(&state);
return 0;
}
int smp_call_wait(handler_wrapper_t *wrapper)
{
int i;
for (i = 0; i < num_cores; i++)
while (wrapper->wait_list[i])
;
spin_unlock(&wrapper->lock);
return 0;
}
/* Perform any initialization needed by per_cpu_info. Right now, this just
* inits the amsg list. Make sure every core calls this at some point in the
* smp_boot process. */
void __arch_pcpu_init(uint32_t coreid)
{
// Switch to the real L1 page table, rather than the boot page table
// which has the [0,KERNSIZE-1] identity mapping.
extern pte_t l1pt[NPTENTRIES];
lcr3(PADDR(l1pt));
register uintptr_t sp asm("sp");
set_stack_top(ROUNDUP(sp, PGSIZE));
}