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 <zide.chen@intel.com>
This commit is contained in:
Zide Chen 2020-02-10 14:09:05 -08:00 committed by Andrew Boie
commit 87b65c5ac2
4 changed files with 25 additions and 3 deletions

View file

@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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);