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:
Tomas Hruby 2010-09-15 14:10:30 +00:00
parent d37b7ebc0b
commit 9e12630d75
8 changed files with 123 additions and 72 deletions

View file

@ -294,6 +294,11 @@ PUBLIC void ioapic_eoi(int 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)
{
i8259_disable();
@ -389,16 +394,19 @@ PUBLIC void ioapic_mask_irq(unsigned irq)
irq_8259_mask(irq);
}
PUBLIC void apic_ipi_sched_handler(void)
{
}
PUBLIC void apic_ipi_halt_handler(void)
{
}
PUBLIC unsigned int apicid(void)
{
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))
{
u32_t tcrt;
@ -793,10 +801,8 @@ PRIVATE struct gate_table_s gate_table_common[] = {
#ifdef CONFIG_SMP
PRIVATE struct gate_table_s gate_table_smp[] = {
{ smp_ipi_sched, SMP_SCHED_PROC, INTR_PRIVILEGE },
{ smp_ipi_dequeue, SMP_DEQUEUE_PROC, INTR_PRIVILEGE },
{ smp_ipi_reboot,SMP_CPU_REBOOT, INTR_PRIVILEGE },
{ smp_ipi_stop, SMP_CPU_HALT, INTR_PRIVILEGE },
{ apic_ipi_sched_intr, APIC_SMP_SCHED_PROC_VECTOR, INTR_PRIVILEGE },
{ apic_ipi_halt_intr, APIC_SMP_CPU_HALT_VECTOR, INTR_PRIVILEGE },
{ NULL, 0, 0}
};
#endif
@ -909,6 +915,45 @@ PUBLIC int detect_ioapics(void)
#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)
{
int timeout;
@ -919,6 +964,8 @@ PUBLIC int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
for (i = 0; i < 2; i++) {
u32_t val;
/* clear err status */
lapic_errstatus();
/* set target pe */
@ -938,8 +985,8 @@ PUBLIC int apic_send_startup_ipi(unsigned cpu, phys_bytes trampoline)
lapic_microsec_sleep (200);
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();
timeout--;
if (!timeout) break;

View file

@ -88,6 +88,8 @@
#define IOAPIC_REDIR_TABLE 0x10
#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_SPURIOUS_INT_VECTOR 0xff
@ -157,12 +159,31 @@ _PROTOTYPE(void ioapic_unset_irq, (unsigned irq));
/* signal the end of interrupt handler to apic */
_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 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>
#define cpu_feature_apic_on_chip() _cpufeature(_CPUF_I386_APIC_ON_CHIP)

View file

@ -68,26 +68,12 @@ ENTRY(lapic_timer_int_handler)
lapic_intr(_C_LABEL(timer_int_handler))
#ifdef CONFIG_SMP
#include "arch_smp.h"
/* FIXME dummy stubs */
ENTRY(smp_ipi_sched)
1: jmp 1b
ENTRY(apic_ipi_sched_intr)
lapic_intr(_C_LABEL(apic_ipi_sched_handler))
ENTRY(smp_ipi_dequeue)
1: jmp 1b
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
ENTRY(apic_ipi_halt_intr)
lapic_intr(_C_LABEL(apic_ipi_halt_handler))
#endif /* CONFIG_SMP */

View file

@ -126,13 +126,10 @@ PRIVATE void smp_start_aps(void)
* using the processor's apic id values.
*/
for (cpu = 0; cpu < ncpus; cpu++) {
printf("Booting cpu %d\n", cpu);
ap_cpu_ready = -1;
/* Don't send INIT/SIPI to boot cpu. */
if((apicid() == cpuid2apicid[cpu]) &&
(apicid() == bsp_lapic_id)) {
cpu_set_flag(cpu, CPU_IS_READY);
printf("Skiping bsp\n");
continue;
}
@ -150,7 +147,6 @@ PRIVATE void smp_start_aps(void)
while (lapic_read(LAPIC_TIMER_CCR)) {
if (ap_cpu_ready == cpu) {
printf("CPU %d is up\n", cpu);
cpu_set_flag(cpu, CPU_IS_READY);
break;
}
@ -176,14 +172,42 @@ PUBLIC void smp_halt_cpu (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)
{
unsigned cpu = cpuid;
printf("CPU %d says hello world!\n", cpu);
/* inform the world of our presence. */
ap_cpu_ready = cpu;
@ -222,12 +246,6 @@ PRIVATE void ap_finish_booting(void)
ap_boot_finished(cpu);
spinlock_unlock(&boot_lock);
/* finish processor initialisation. */
lapic_enable(cpu);
BKL_UNLOCK();
for(;;);
switch_to_user();
NOT_REACHABLE;
}

View file

@ -69,8 +69,9 @@ PRIVATE void pagefault( struct proc *pr,
/* Page fault we can't / don't want to
* handle.
*/
printf("pagefault for process %d ('%s'), pc = 0x%x, addr = 0x%x, flags = 0x%x, is_nested %d\n",
pr->p_endpoint, pr->p_name, pr->p_reg.pc,
printf("pagefault for process %d ('%s') on CPU %d, "
"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);
proc_stacktrace(pr);
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);
else
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, "
"cs= 0x%x, eflags= 0x%x trap_esp 0x%08x\n",

View file

@ -5,21 +5,6 @@
#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__
/* returns the current cpu id */
@ -31,6 +16,8 @@
*/
#define smp_single_cpu_fallback() do { \
tss_init(0, get_k_stack_top(0)); \
bsp_cpu_id = 0; \
ncpus = 1; \
bsp_finish_booting(); \
} while(0)

View file

@ -23,7 +23,5 @@ void wait_for_APs_to_finish_booting(void)
void ap_boot_finished(unsigned cpu)
{
printf("CPU %d is running\n", cpu);
ap_cpus_booted++;
}

View file

@ -28,13 +28,6 @@ EXTERN unsigned bsp_cpu_id;
*/
_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_READY 2