PRIVATE unsigned apic_imcrp;
PRIVATE const unsigned nlints = 0;
-#define apic_eoi() do { *((volatile u32_t *) lapic_eoi_addr) = 0; } while(0)
+PUBLIC void arch_eoi(void)
+{
+ apic_eoi();
+}
/*
* FIXME this should be a cpulocal variable but there are some problems with
irq_8259_mask(irq);
}
-PUBLIC void apic_ipi_sched_handler(void)
-{
-}
-
PUBLIC unsigned int apicid(void)
{
return lapic_read(LAPIC_ID);
lapic_write(LAPIC_LVTTR, lvtt | APIC_LVTT_MASK);
}
+PUBLIC void lapic_restart_timer(void)
+{
+ u32_t lvtt;
+ lvtt = lapic_read(LAPIC_LVTTR);
+ lapic_write(LAPIC_LVTTR, lvtt & ~APIC_LVTT_MASK);
+}
+
PUBLIC void lapic_microsec_sleep(unsigned count)
{
lapic_set_timer_one_shot(count);
_PROTOTYPE(void lapic_set_timer_periodic, (const unsigned freq));
_PROTOTYPE(void lapic_set_timer_one_shot, (const u32_t value));
_PROTOTYPE(void lapic_stop_timer, (void));
+_PROTOTYPE(void lapic_restart_timer, (void));
_PROTOTYPE(void ioapic_set_irq, (unsigned irq));
_PROTOTYPE(void ioapic_unset_irq, (unsigned irq));
- /* signal the end of interrupt handler to apic */
+/* signal the end of interrupt handler to apic */
+#define apic_eoi() do { *((volatile u32_t *) lapic_eoi_addr) = 0; } while(0)
+
_PROTOTYPE(void ioapic_eoi, (int irq));
_PROTOTYPE(void dump_apic_irq_state, (void));
_PROTOTYPE(void apic_ipi_sched_intr, (void));
_PROTOTYPE(void apic_ipi_halt_intr, (void));
-_PROTOTYPE(void apic_ipi_sched_handler, (void));
-
#define APIC_IPI_DEST 0
#define APIC_IPI_SELF 1
#define APIC_IPI_TO_ALL 2
#ifdef CONFIG_SMP
ENTRY(apic_ipi_sched_intr)
- lapic_intr(_C_LABEL(apic_ipi_sched_handler))
+ lapic_intr(_C_LABEL(smp_ipi_sched_handler))
ENTRY(apic_ipi_halt_intr)
lapic_intr(_C_LABEL(smp_ipi_halt_handler))
#include "kernel/clock.h"
#include "kernel/proc.h"
+#include "kernel/interrupt.h"
#include <minix/u64.h>
#include "glo.h"
#ifdef CONFIG_APIC
if (lapic_addr) {
lapic_stop_timer();
+ apic_eoi();
} else
#endif
{
}
}
+PUBLIC void arch_restart_local_timer(void)
+{
+#ifdef CONFIG_APIC
+ if (lapic_addr) {
+ lapic_restart_timer();
+ } else
+#endif
+ {
+ init_8253A_timer(system_hz);
+ }
+}
+
PUBLIC int arch_register_local_timer_handler(const irq_handler_t handler)
{
#ifdef CONFIG_APIC
PUBLIC void context_stop_idle(void)
{
- context_stop(proc_addr(IDLE));
+ int is_idle;
+ unsigned cpu = cpuid;
+
+ is_idle = get_cpu_var(cpu, cpu_is_idle);
+ get_cpu_var(cpu, cpu_is_idle) = 0;
+
+ context_stop(get_cpulocal_var_ptr(idle_proc));
+
+ if (is_idle)
+ arch_restart_local_timer();
}
PUBLIC u64_t ms_2_cpu_time(unsigned ms)
BKL_UNLOCK();
for(;;);
}
+
+PUBLIC void arch_send_smp_schedule_ipi(unsigned cpu)
+{
+ apic_send_ipi(APIC_SMP_SCHED_PROC_VECTOR, cpu, APIC_IPI_DEST);
+}
ioapic_reset_pic(); \
lapic_disable(); \
} while (0)
+#ifdef CONFIG_SMP
+#define ipi_ack apic_eoi
+#endif
#else
/* legacy PIC */
_PROTOTYPE(int timer_int_handler, (void));
_PROTOTYPE(int arch_init_local_timer, (unsigned freq));
+/* sto p the local timer ticking */
_PROTOTYPE(void arch_stop_local_timer, (void));
+/* let the time tick again with the original settings after it was stopped */
+_PROTOTYPE(void arch_restart_local_timer, (void));
_PROTOTYPE(int arch_register_local_timer_handler, (irq_handler_t handler));
_PROTOTYPE( u64_t ms_2_cpu_time, (unsigned ms));
/* CPU private run queues */
DECLARE_CPULOCAL(struct proc *, run_q_head[NR_SCHED_QUEUES]); /* ptrs to ready list headers */
DECLARE_CPULOCAL(struct proc *, run_q_tail[NR_SCHED_QUEUES]); /* ptrs to ready list tails */
+DECLARE_CPULOCAL(int, cpu_is_idle); /* let the others know that you are idle */
DECLARE_CPULOCAL(u64_t ,tsc_ctr_switch); /* when did we switched time accounting */
--- /dev/null
+#ifndef __INTERRUPT_H__
+#define __INTERRUPT_H__
+
+#include "hw_intr.h"
+
+#endif /* __INTERRUPT_H__ */
/* initialize IDLE structures for every CPU */
for (i = 0; i < CONFIG_MAX_CPUS; i++) {
struct proc * ip = get_cpu_var_ptr(i, idle_proc);
+ ip->p_endpoint = IDLE;
ip->p_priv = &idle_priv;
/* must not let idle ever get scheduled */
ip->p_rts_flags |= RTS_PROC_STOP;
switch_address_space_idle();
+ /* we don't need to keep time on APs as it is handled on the BSP */
+ if (cpuid != bsp_cpu_id)
+ arch_stop_local_timer();
+ get_cpulocal_var(cpu_is_idle) = 1;
+
/* start accounting for the idle time */
context_stop(proc_addr(KERNEL));
halt_cpu();
* process is assigned to.
*/
int q = rp->p_priority; /* scheduling queue to use */
- struct proc * p;
struct proc **rdy_head, **rdy_tail;
assert(proc_is_runnable(rp));
rp->p_nextready = NULL; /* mark new end */
}
+ if (cpuid == rp->p_cpu) {
+ /*
+ * enqueueing a process with a higher priority than the current one,
+ * it gets preempted. The current process must be preemptible. Testing
+ * the priority also makes sure that a process does not preempt itself
+ */
+ struct proc * p;
+ p = get_cpulocal_var(proc_ptr);
+ assert(p);
+ if((p->p_priority > rp->p_priority) &&
+ (priv(p)->s_flags & PREEMPTIBLE))
+ RTS_SET(p, RTS_PREEMPTED); /* calls dequeue() */
+ }
+#ifdef CONFIG_SMP
/*
- * enqueueing a process with a higher priority than the current one, it gets
- * preempted. The current process must be preemptible. Testing the priority
- * also makes sure that a process does not preempt itself
+ * if the process was enqueued on a different cpu and the cpu is idle, i.e.
+ * the time is off, we need to wake up that cpu and let it schedule this new
+ * process
*/
- p = get_cpulocal_var(proc_ptr);
- assert(p);
- if((p->p_priority > rp->p_priority) &&
- (priv(p)->s_flags & PREEMPTIBLE))
- RTS_SET(p, RTS_PREEMPTED); /* calls dequeue() */
+ else if (get_cpu_var(rp->p_cpu, cpu_is_idle)) {
+ smp_schedule(rp->p_cpu);
+ }
+#endif
#if DEBUG_SANITYCHECKS
assert(runqueues_ok_local());
#include "smp.h"
+#include "interrupt.h"
unsigned ncpus;
unsigned ht_per_core;
PUBLIC void smp_ipi_halt_handler(void)
{
+ ipi_ack();
arch_stop_local_timer();
arch_smp_halt_cpu();
}
+PUBLIC void smp_schedule(unsigned cpu)
+{
+ arch_send_smp_schedule_ipi(cpu);
+}
+
+PUBLIC void smp_ipi_sched_handler(void)
+{
+ struct proc * p;
+
+ ipi_ack();
+
+ p = get_cpulocal_var(proc_ptr);
+
+ if (p->p_endpoint != IDLE)
+ RTS_SET(p, RTS_PREEMPTED); /* calls dequeue() */
+}
+
_PROTOTYPE(void wait_for_APs_to_finish_booting, (void));
_PROTOTYPE(void ap_boot_finished, (unsigned cpu));
+
+/* IPI handlers */
_PROTOTYPE(void smp_ipi_halt_handler, (void));
+_PROTOTYPE(void smp_ipi_sched_handler, (void));
+
+_PROTOTYPE(void smp_schedule, (unsigned cpu));
+
+_PROTOTYPE(void arch_send_smp_schedule_ipi, (unsigned cpu));
_PROTOTYPE(void arch_smp_halt_cpu, (void));
#endif /* __ASSEMBLY__ */