SMP - APs are fully enabled
- apic_send_ipi() to send inter-processor interrupts (IPIs) - APIC IPI schedule and halt handlers to signal x-cpu that a cpu shold reschedule or halt - various little changes to let APs run - no processes are scheduled at the APs and therefore they are idle except being interrupted by a timer time to time
This commit is contained in:
parent
d37b7ebc0b
commit
9e12630d75
8 changed files with 123 additions and 72 deletions
|
@ -294,6 +294,11 @@ PUBLIC void ioapic_eoi(int irq)
|
||||||
irq_8259_eoi(irq);
|
irq_8259_eoi(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PUBLIC void ioapic_set_id(u32_t addr, unsigned int id)
|
||||||
|
{
|
||||||
|
ioapic_write(addr, IOAPIC_ID, id << 24);
|
||||||
|
}
|
||||||
|
|
||||||
PUBLIC int ioapic_enable_all(void)
|
PUBLIC int ioapic_enable_all(void)
|
||||||
{
|
{
|
||||||
i8259_disable();
|
i8259_disable();
|
||||||
|
@ -389,16 +394,19 @@ PUBLIC void ioapic_mask_irq(unsigned irq)
|
||||||
irq_8259_mask(irq);
|
irq_8259_mask(irq);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PUBLIC void apic_ipi_sched_handler(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PUBLIC void apic_ipi_halt_handler(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
PUBLIC unsigned int apicid(void)
|
PUBLIC unsigned int apicid(void)
|
||||||
{
|
{
|
||||||
return lapic_read(LAPIC_ID);
|
return lapic_read(LAPIC_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
PUBLIC void ioapic_set_id(u32_t addr, unsigned int id)
|
|
||||||
{
|
|
||||||
ioapic_write(addr, IOAPIC_ID, id << 24);
|
|
||||||
}
|
|
||||||
|
|
||||||
PRIVATE int calib_clk_handler(irq_hook_t * UNUSED(hook))
|
PRIVATE int calib_clk_handler(irq_hook_t * UNUSED(hook))
|
||||||
{
|
{
|
||||||
u32_t tcrt;
|
u32_t tcrt;
|
||||||
|
@ -793,10 +801,8 @@ PRIVATE struct gate_table_s gate_table_common[] = {
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
PRIVATE struct gate_table_s gate_table_smp[] = {
|
PRIVATE struct gate_table_s gate_table_smp[] = {
|
||||||
{ smp_ipi_sched, SMP_SCHED_PROC, INTR_PRIVILEGE },
|
{ apic_ipi_sched_intr, APIC_SMP_SCHED_PROC_VECTOR, INTR_PRIVILEGE },
|
||||||
{ smp_ipi_dequeue, SMP_DEQUEUE_PROC, INTR_PRIVILEGE },
|
{ apic_ipi_halt_intr, APIC_SMP_CPU_HALT_VECTOR, INTR_PRIVILEGE },
|
||||||
{ smp_ipi_reboot,SMP_CPU_REBOOT, INTR_PRIVILEGE },
|
|
||||||
{ smp_ipi_stop, SMP_CPU_HALT, INTR_PRIVILEGE },
|
|
||||||
{ NULL, 0, 0}
|
{ NULL, 0, 0}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -909,6 +915,45 @@ PUBLIC int detect_ioapics(void)
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
|
|
||||||
|
PUBLIC void apic_send_ipi(unsigned vector, unsigned cpu, int type)
|
||||||
|
{
|
||||||
|
u32_t icr1, icr2;
|
||||||
|
|
||||||
|
if (ncpus == 1)
|
||||||
|
/* no need of sending an IPI */
|
||||||
|
return;
|
||||||
|
|
||||||
|
while (lapic_read_icr1() & APIC_ICR_DELIVERY_PENDING)
|
||||||
|
arch_pause();
|
||||||
|
|
||||||
|
icr1 = lapic_read_icr1() & 0xFFF0F800;
|
||||||
|
icr2 = lapic_read_icr2() & 0xFFFFFF;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case APIC_IPI_DEST:
|
||||||
|
if (!cpu_is_ready(cpu))
|
||||||
|
return;
|
||||||
|
lapic_write_icr2(icr2 | (cpuid2apicid[cpu] << 24));
|
||||||
|
lapic_write_icr1(icr1 | APIC_ICR_DEST_FIELD | vector);
|
||||||
|
break;
|
||||||
|
case APIC_IPI_SELF:
|
||||||
|
lapic_write_icr2(icr2);
|
||||||
|
lapic_write_icr1(icr1 | APIC_ICR_DEST_SELF | vector);
|
||||||
|
break;
|
||||||
|
case APIC_IPI_TO_ALL_BUT_SELF:
|
||||||
|
lapic_write_icr2(icr2);
|
||||||
|
lapic_write_icr1(icr1 | APIC_ICR_DEST_ALL_BUT_SELF | vector);
|
||||||
|
break;
|
||||||
|
case APIC_IPI_TO_ALL:
|
||||||
|
lapic_write_icr2(icr2);
|
||||||
|
lapic_write_icr1(icr1 | APIC_ICR_DEST_ALL | vector);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("WARNING : unknown send ipi type request\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
PUBLIC int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
|
PUBLIC int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
|
||||||
{
|
{
|
||||||
int timeout;
|
int timeout;
|
||||||
|
@ -919,6 +964,8 @@ PUBLIC int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
u32_t val;
|
u32_t val;
|
||||||
|
|
||||||
|
/* clear err status */
|
||||||
lapic_errstatus();
|
lapic_errstatus();
|
||||||
|
|
||||||
/* set target pe */
|
/* set target pe */
|
||||||
|
@ -938,8 +985,8 @@ PUBLIC int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
|
||||||
lapic_microsec_sleep (200);
|
lapic_microsec_sleep (200);
|
||||||
errstatus = 0;
|
errstatus = 0;
|
||||||
|
|
||||||
while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) && !errstatus)
|
while ((lapic_read(LAPIC_ICR1) & APIC_ICR_DELIVERY_PENDING) &&
|
||||||
{
|
!errstatus) {
|
||||||
errstatus = lapic_errstatus();
|
errstatus = lapic_errstatus();
|
||||||
timeout--;
|
timeout--;
|
||||||
if (!timeout) break;
|
if (!timeout) break;
|
||||||
|
|
|
@ -88,6 +88,8 @@
|
||||||
#define IOAPIC_REDIR_TABLE 0x10
|
#define IOAPIC_REDIR_TABLE 0x10
|
||||||
|
|
||||||
#define APIC_TIMER_INT_VECTOR 0xf0
|
#define APIC_TIMER_INT_VECTOR 0xf0
|
||||||
|
#define APIC_SMP_SCHED_PROC_VECTOR 0xf1
|
||||||
|
#define APIC_SMP_CPU_HALT_VECTOR 0xf2
|
||||||
#define APIC_ERROR_INT_VECTOR 0xfe
|
#define APIC_ERROR_INT_VECTOR 0xfe
|
||||||
#define APIC_SPURIOUS_INT_VECTOR 0xff
|
#define APIC_SPURIOUS_INT_VECTOR 0xff
|
||||||
|
|
||||||
|
@ -157,12 +159,31 @@ _PROTOTYPE(void ioapic_unset_irq, (unsigned irq));
|
||||||
/* signal the end of interrupt handler to apic */
|
/* signal the end of interrupt handler to apic */
|
||||||
_PROTOTYPE(void ioapic_eoi, (int irq));
|
_PROTOTYPE(void ioapic_eoi, (int irq));
|
||||||
|
|
||||||
_PROTOTYPE(void lapic_disable, (void));
|
|
||||||
_PROTOTYPE(void ioapic_disable_all, (void));
|
|
||||||
_PROTOTYPE(void ioapic_reset_pic, (void));
|
|
||||||
|
|
||||||
_PROTOTYPE(void dump_apic_irq_state, (void));
|
_PROTOTYPE(void dump_apic_irq_state, (void));
|
||||||
|
|
||||||
|
_PROTOTYPE(void apic_send_ipi, (unsigned vector, unsigned cpu, int type));
|
||||||
|
|
||||||
|
_PROTOTYPE(void apic_ipi_sched_intr, (void));
|
||||||
|
_PROTOTYPE(void apic_ipi_halt_intr, (void));
|
||||||
|
|
||||||
|
_PROTOTYPE(void apic_ipi_sched_handler, (void));
|
||||||
|
_PROTOTYPE(void apic_ipi_halt_handler, (void));
|
||||||
|
|
||||||
|
#define APIC_IPI_DEST 0
|
||||||
|
#define APIC_IPI_SELF 1
|
||||||
|
#define APIC_IPI_TO_ALL 2
|
||||||
|
#define APIC_IPI_TO_ALL_BUT_SELF 3
|
||||||
|
|
||||||
|
#define apic_send_ipi_single(vector,cpu) \
|
||||||
|
apic_send_ipi(vector, cpu, APIC_IPI_DEST);
|
||||||
|
#define apic_send_ipi_self(vector) \
|
||||||
|
apic_send_ipi(vector, 0, APIC_IPI_SELF)
|
||||||
|
#define apic_send_ipi_all(vector) \
|
||||||
|
apic_send_ipi (vector, 0, APIC_IPI_TO_ALL)
|
||||||
|
#define apic_send_ipi_allbutself(vector) \
|
||||||
|
apic_send_ipi (vector, 0, APIC_IPI_TO_ALL_BUT_SELF);
|
||||||
|
|
||||||
|
|
||||||
#include <minix/cpufeature.h>
|
#include <minix/cpufeature.h>
|
||||||
|
|
||||||
#define cpu_feature_apic_on_chip() _cpufeature(_CPUF_I386_APIC_ON_CHIP)
|
#define cpu_feature_apic_on_chip() _cpufeature(_CPUF_I386_APIC_ON_CHIP)
|
||||||
|
|
|
@ -68,26 +68,12 @@ ENTRY(lapic_timer_int_handler)
|
||||||
lapic_intr(_C_LABEL(timer_int_handler))
|
lapic_intr(_C_LABEL(timer_int_handler))
|
||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
#include "arch_smp.h"
|
|
||||||
|
|
||||||
/* FIXME dummy stubs */
|
ENTRY(apic_ipi_sched_intr)
|
||||||
ENTRY(smp_ipi_sched)
|
lapic_intr(_C_LABEL(apic_ipi_sched_handler))
|
||||||
1: jmp 1b
|
|
||||||
|
|
||||||
ENTRY(smp_ipi_dequeue)
|
ENTRY(apic_ipi_halt_intr)
|
||||||
1: jmp 1b
|
lapic_intr(_C_LABEL(apic_ipi_halt_handler))
|
||||||
|
|
||||||
ENTRY(smp_ipi_stop)
|
|
||||||
1: jmp 1b
|
|
||||||
|
|
||||||
ENTRY(smp_ipi_reboot)
|
|
||||||
1: jmp 1b
|
|
||||||
|
|
||||||
ENTRY(smp_ipi_err_int)
|
|
||||||
1: jmp 1b
|
|
||||||
|
|
||||||
ENTRY(smp_ipi_spv_int)
|
|
||||||
1: jmp 1b
|
|
||||||
|
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
|
|
|
@ -126,13 +126,10 @@ PRIVATE void smp_start_aps(void)
|
||||||
* using the processor's apic id values.
|
* using the processor's apic id values.
|
||||||
*/
|
*/
|
||||||
for (cpu = 0; cpu < ncpus; cpu++) {
|
for (cpu = 0; cpu < ncpus; cpu++) {
|
||||||
printf("Booting cpu %d\n", cpu);
|
|
||||||
ap_cpu_ready = -1;
|
ap_cpu_ready = -1;
|
||||||
/* Don't send INIT/SIPI to boot cpu. */
|
/* Don't send INIT/SIPI to boot cpu. */
|
||||||
if((apicid() == cpuid2apicid[cpu]) &&
|
if((apicid() == cpuid2apicid[cpu]) &&
|
||||||
(apicid() == bsp_lapic_id)) {
|
(apicid() == bsp_lapic_id)) {
|
||||||
cpu_set_flag(cpu, CPU_IS_READY);
|
|
||||||
printf("Skiping bsp\n");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +147,6 @@ PRIVATE void smp_start_aps(void)
|
||||||
|
|
||||||
while (lapic_read(LAPIC_TIMER_CCR)) {
|
while (lapic_read(LAPIC_TIMER_CCR)) {
|
||||||
if (ap_cpu_ready == cpu) {
|
if (ap_cpu_ready == cpu) {
|
||||||
printf("CPU %d is up\n", cpu);
|
|
||||||
cpu_set_flag(cpu, CPU_IS_READY);
|
cpu_set_flag(cpu, CPU_IS_READY);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -176,14 +172,42 @@ PUBLIC void smp_halt_cpu (void)
|
||||||
|
|
||||||
PUBLIC void smp_shutdown_aps (void)
|
PUBLIC void smp_shutdown_aps (void)
|
||||||
{
|
{
|
||||||
NOT_IMPLEMENTED;
|
u8_t cpu;
|
||||||
|
unsigned aid = apicid();
|
||||||
|
|
||||||
|
if (ncpus == 1)
|
||||||
|
goto exit_shutdown_aps;
|
||||||
|
|
||||||
|
for (cpu = 0; cpu < ncpus; cpu++) {
|
||||||
|
u16_t i;
|
||||||
|
if (!cpu_is_ready(cpu))
|
||||||
|
continue;
|
||||||
|
if ((aid == cpuid2apicid[cpu]) && (aid == bsp_lapic_id))
|
||||||
|
continue;
|
||||||
|
apic_send_ipi(APIC_SMP_CPU_HALT_VECTOR, cpu, APIC_IPI_DEST);
|
||||||
|
/* TODO wait for the cpu to be down */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sending INIT to a processor makes it to wait in a halt state */
|
||||||
|
for (cpu = 0; cpu < ncpus; cpu++) {
|
||||||
|
if ((aid == cpuid2apicid[cpu]) && (aid == bsp_lapic_id))
|
||||||
|
continue;
|
||||||
|
apic_send_init_ipi (cpu, 0);
|
||||||
|
}
|
||||||
|
exit_shutdown_aps:
|
||||||
|
ioapic_disable_all();
|
||||||
|
|
||||||
|
lapic_disable();
|
||||||
|
|
||||||
|
ncpus = 1; /* hopefully !!! */
|
||||||
|
lapic_addr = lapic_eoi_addr = 0;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRIVATE void ap_finish_booting(void)
|
PRIVATE void ap_finish_booting(void)
|
||||||
{
|
{
|
||||||
unsigned cpu = cpuid;
|
unsigned cpu = cpuid;
|
||||||
|
|
||||||
printf("CPU %d says hello world!\n", cpu);
|
|
||||||
/* inform the world of our presence. */
|
/* inform the world of our presence. */
|
||||||
ap_cpu_ready = cpu;
|
ap_cpu_ready = cpu;
|
||||||
|
|
||||||
|
@ -222,12 +246,6 @@ PRIVATE void ap_finish_booting(void)
|
||||||
ap_boot_finished(cpu);
|
ap_boot_finished(cpu);
|
||||||
spinlock_unlock(&boot_lock);
|
spinlock_unlock(&boot_lock);
|
||||||
|
|
||||||
/* finish processor initialisation. */
|
|
||||||
lapic_enable(cpu);
|
|
||||||
|
|
||||||
BKL_UNLOCK();
|
|
||||||
for(;;);
|
|
||||||
|
|
||||||
switch_to_user();
|
switch_to_user();
|
||||||
NOT_REACHABLE;
|
NOT_REACHABLE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,8 +69,9 @@ PRIVATE void pagefault( struct proc *pr,
|
||||||
/* Page fault we can't / don't want to
|
/* Page fault we can't / don't want to
|
||||||
* handle.
|
* handle.
|
||||||
*/
|
*/
|
||||||
printf("pagefault for process %d ('%s'), pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n",
|
printf("pagefault for process %d ('%s') on CPU %d, "
|
||||||
pr->p_endpoint, pr->p_name, pr->p_reg.pc,
|
"pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n",
|
||||||
|
pr->p_endpoint, pr->p_name, cpuid, pr->p_reg.pc,
|
||||||
pagefaultcr2, frame->errcode, is_nested);
|
pagefaultcr2, frame->errcode, is_nested);
|
||||||
proc_stacktrace(pr);
|
proc_stacktrace(pr);
|
||||||
printf("pc of pagefault: 0x%lx\n", frame->eip);
|
printf("pc of pagefault: 0x%lx\n", frame->eip);
|
||||||
|
@ -207,7 +208,7 @@ PUBLIC void exception_handler(int is_nested, struct exception_frame * frame)
|
||||||
printf("\nIntel-reserved exception %d\n", frame->vector);
|
printf("\nIntel-reserved exception %d\n", frame->vector);
|
||||||
else
|
else
|
||||||
printf("\n%s\n", ep->msg);
|
printf("\n%s\n", ep->msg);
|
||||||
printf("is_nested = %d ", is_nested);
|
printf("cpu %d is_nested = %d ", cpuid, is_nested);
|
||||||
|
|
||||||
printf("vec_nr= %d, trap_errno= 0x%x, eip= 0x%x, "
|
printf("vec_nr= %d, trap_errno= 0x%x, eip= 0x%x, "
|
||||||
"cs= 0x%x, eflags= 0x%x trap_esp 0x%08x\n",
|
"cs= 0x%x, eflags= 0x%x trap_esp 0x%08x\n",
|
||||||
|
|
|
@ -5,21 +5,6 @@
|
||||||
|
|
||||||
#define MAX_NR_INTERRUPT_ENTRIES 128
|
#define MAX_NR_INTERRUPT_ENTRIES 128
|
||||||
|
|
||||||
#define SMP_SCHED_PROC 0xF0
|
|
||||||
#define SMP_DEQUEUE_PROC 0xF1
|
|
||||||
#define SMP_CPU_REBOOT 0xF2
|
|
||||||
#define SMP_CPU_HALT 0xF3
|
|
||||||
#define SMP_ERROR_INT 0xF4
|
|
||||||
|
|
||||||
/* currently only 2 interrupt priority levels are used */
|
|
||||||
#define SPL0 0x0
|
|
||||||
#define SPLHI 0xF
|
|
||||||
|
|
||||||
#define SMP_IPI_DEST 0
|
|
||||||
#define SMP_IPI_SELF 1
|
|
||||||
#define SMP_IPI_TO_ALL 2
|
|
||||||
#define SMP_IPI_TO_ALL_BUT_SELF 3
|
|
||||||
|
|
||||||
#ifndef __ASSEMBLY__
|
#ifndef __ASSEMBLY__
|
||||||
|
|
||||||
/* returns the current cpu id */
|
/* returns the current cpu id */
|
||||||
|
@ -31,6 +16,8 @@
|
||||||
*/
|
*/
|
||||||
#define smp_single_cpu_fallback() do { \
|
#define smp_single_cpu_fallback() do { \
|
||||||
tss_init(0, get_k_stack_top(0)); \
|
tss_init(0, get_k_stack_top(0)); \
|
||||||
|
bsp_cpu_id = 0; \
|
||||||
|
ncpus = 1; \
|
||||||
bsp_finish_booting(); \
|
bsp_finish_booting(); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,5 @@ void wait_for_APs_to_finish_booting(void)
|
||||||
|
|
||||||
void ap_boot_finished(unsigned cpu)
|
void ap_boot_finished(unsigned cpu)
|
||||||
{
|
{
|
||||||
printf("CPU %d is running\n", cpu);
|
|
||||||
|
|
||||||
ap_cpus_booted++;
|
ap_cpus_booted++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,13 +28,6 @@ EXTERN unsigned bsp_cpu_id;
|
||||||
*/
|
*/
|
||||||
_PROTOTYPE(void smp_init, (void));
|
_PROTOTYPE(void smp_init, (void));
|
||||||
|
|
||||||
_PROTOTYPE(void smp_ipi_err_int, (void));
|
|
||||||
_PROTOTYPE(void smp_ipi_spv_int, (void));
|
|
||||||
_PROTOTYPE(void smp_ipi_sched, (void));
|
|
||||||
_PROTOTYPE(void smp_ipi_dequeue, (void));
|
|
||||||
_PROTOTYPE(void smp_ipi_stop, (void));
|
|
||||||
_PROTOTYPE(void smp_ipi_reboot, (void));
|
|
||||||
|
|
||||||
#define CPU_IS_BSP 1
|
#define CPU_IS_BSP 1
|
||||||
#define CPU_IS_READY 2
|
#define CPU_IS_READY 2
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue