Arch independent per-cpu initialization
[akaros.git] / kern / src / smp.c
index 8c6c924..dc4e86f 100644 (file)
@@ -11,7 +11,7 @@
 #include <arch/arch.h>
 #include <atomic.h>
 #include <smp.h>
-#include <ros/error.h>
+#include <error.h>
 #include <stdio.h>
 #include <string.h>
 #include <assert.h>
@@ -31,24 +31,67 @@ atomic_t outstanding_calls = 0;
  * - Management cores (core 0 for now) call manager, which should never return.
  * - Worker cores halt and wake up when interrupted, do any work on their work
  *   queue, then halt again.
- *
- * TODO: think about resetting the stack pointer at the beginning for worker
- * cores. (keeps the stack from growing if we never go back to userspace).
  * TODO: think about unifying the manager into a workqueue function, so we don't
  * need to check mgmt_core in here.  it gets a little ugly, since there are
  * other places where we check for mgmt and might not smp_idle / call manager.
  */
-void smp_idle(void)
+static void __smp_idle(void)
 {
+       int8_t state = 0;
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+
+       /* There was a process running here, and we should return to it */
+       if (pcpui->cur_tf) {                    /* aka, current_tf */
+               assert(pcpui->cur_proc);        /* aka, current */
+               proc_restartcore();
+               assert(0);
+       }
+       /* if we made it here, we truly want to idle */
+       /* in the future, we may need to proactively leave process context here.
+        * for now, it is possible to have a current loaded, even if we are idle
+        * (and presumably about to execute a kmsg or fire up a vcore). */
        if (!management_core()) {
                enable_irq();
                while (1) {
-                       process_workqueue();
-                       // consider races with work added after we started leaving the last func
+                       process_routine_kmsg(0);
                        cpu_halt();
                }
        } else {
+               enable_irqsave(&state);
+               /* this makes us wait to enter the manager til any IO is done (totally
+                * arbitrary 10ms), so we can handle the routine message that we
+                * currently use to do the completion.  Note this also causes us to wait
+                * 10ms regardless of how long the IO takes.  This all needs work. */
+               //udelay(10000); /* done in the manager for now */
+               process_routine_kmsg(0);
+               disable_irqsave(&state);
                manager();
        }
        assert(0);
 }
+
+void smp_idle(void)
+{
+       #ifdef __CONFIG_RESET_STACKS__
+       set_stack_pointer(get_stack_top());
+       #endif /* __CONFIG_RESET_STACKS__ */
+       __smp_idle();
+       assert(0);
+}
+
+/* Arch-independent per-cpu initialization.  This will call the arch dependent
+ * init first. */
+void smp_percpu_init(void)
+{
+       uint32_t coreid = core_id();
+       /* Do this first */
+       __arch_pcpu_init(coreid);
+       per_cpu_info[coreid].spare = 0;
+       /* Init relevant lists */
+       spinlock_init(&per_cpu_info[coreid].immed_amsg_lock);
+       STAILQ_INIT(&per_cpu_info[coreid].immed_amsgs);
+       spinlock_init(&per_cpu_info[coreid].routine_amsg_lock);
+       STAILQ_INIT(&per_cpu_info[coreid].routine_amsgs);
+       /* Initialize the per-core timer chain */
+       init_timer_chain(&per_cpu_info[coreid].tchain, set_pcpu_alarm_interrupt);
+}