From 87b65c5ac2df4e59a3c6b7f3469d751ce85269e4 Mon Sep 17 00:00:00 2001 From: Zide Chen Date: Mon, 10 Feb 2020 14:09:05 -0800 Subject: [PATCH] interrupt_controller: program local APIC LDR register for xAPIC If IO APIC is in logical destination mode, local APICs compare their logical APIC ID defined in LDR (Logical Destination Register) with the destination code sent with the interrupt to determine whether or not to accept the incoming interrupt. This patch programs LDR in xAPIC mode to support IO APIC logical mode. The local APIC ID from local APIC ID register can't be used as the 'logical APIC ID' because LAPIC ID may not be consecutive numbers hence it makes it impossible for LDR to encode 8 IDs within 8 bits. This patch chooses 0 for BSP, and for APs, cpu_number which is the index to x86_cpuboot[], which ultimately assigned in z_smp_init[]. Signed-off-by: Zide Chen --- arch/x86/core/ia32/crt0.S | 3 +++ arch/x86/core/intel64/cpu.c | 3 ++- drivers/interrupt_controller/intc_loapic.c | 20 ++++++++++++++++++- include/drivers/interrupt_controller/loapic.h | 2 +- 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/arch/x86/core/ia32/crt0.S b/arch/x86/core/ia32/crt0.S index e611c884274..c5ea161baf4 100644 --- a/arch/x86/core/ia32/crt0.S +++ b/arch/x86/core/ia32/crt0.S @@ -236,6 +236,9 @@ __csSet: lidt z_x86_idt /* load 32-bit operand size IDT */ #ifdef CONFIG_LOAPIC + /* For BSP, cpu_number is 0 */ + xorl %eax, %eax + pushl %eax call z_loapic_enable #endif diff --git a/arch/x86/core/intel64/cpu.c b/arch/x86/core/intel64/cpu.c index 293c9954e8f..44d44a2ce06 100644 --- a/arch/x86/core/intel64/cpu.c +++ b/arch/x86/core/intel64/cpu.c @@ -144,7 +144,8 @@ FUNC_NORETURN void z_x86_cpu_init(struct x86_cpuboot *cpuboot) { x86_sse_init(NULL); - z_loapic_enable(); + /* The internal cpu_number is the index to x86_cpuboot[] */ + z_loapic_enable((unsigned char)(cpuboot - x86_cpuboot)); #ifdef CONFIG_USERSPACE /* Set landing site for 'syscall' instruction */ diff --git a/drivers/interrupt_controller/intc_loapic.c b/drivers/interrupt_controller/intc_loapic.c index 51991ab056f..c2a425c1581 100644 --- a/drivers/interrupt_controller/intc_loapic.c +++ b/drivers/interrupt_controller/intc_loapic.c @@ -71,10 +71,27 @@ static u32_t loapic_device_power_state = DEVICE_PM_ACTIVE_STATE; * Called from early assembly layer (e.g., crt0.S). */ -void z_loapic_enable(void) +void z_loapic_enable(unsigned char cpu_number) { s32_t loApicMaxLvt; /* local APIC Max LVT */ +#ifndef CONFIG_X2APIC + /* + * in xAPIC and flat model, bits 24-31 in LDR (Logical APIC ID) are + * bitmap of target logical APIC ID and it supports maximum 8 local + * APICs. + * + * The logical APIC ID could be arbitrarily selected by system software + * and is different from local APIC ID in local APIC ID register. + * + * We choose 0 for BSP, and the index to x86_cpuboot[] for secondary + * CPUs. + * + * in X2APIC, LDR is read-only. + */ + x86_write_xapic(LOAPIC_LDR, 1 << (cpu_number + 24)); +#endif + /* * enable the local APIC. note that we use xAPIC mode here, since * x2APIC access is not enabled until the next step (if at all). @@ -99,6 +116,7 @@ void z_loapic_enable(void) /* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */ #ifndef CONFIG_X2APIC + /* Flat model */ x86_write_loapic(LOAPIC_DFR, 0xffffffff); /* no DFR in x2APIC mode */ #endif diff --git a/include/drivers/interrupt_controller/loapic.h b/include/drivers/interrupt_controller/loapic.h index 59093408b24..5fbe0662230 100644 --- a/include/drivers/interrupt_controller/loapic.h +++ b/include/drivers/interrupt_controller/loapic.h @@ -54,7 +54,7 @@ extern "C" { #endif -extern void z_loapic_enable(void); +extern void z_loapic_enable(unsigned char cpu_number); extern void z_loapic_int_vec_set(unsigned int irq, unsigned int vector); extern void z_loapic_irq_enable(unsigned int irq); extern void z_loapic_irq_disable(unsigned int irq);