diff --git a/arch/x86/platforms/quark_se/Kconfig b/arch/x86/platforms/quark_se/Kconfig index 594ee1fe752..1a0be3ca17a 100644 --- a/arch/x86/platforms/quark_se/Kconfig +++ b/arch/x86/platforms/quark_se/Kconfig @@ -41,6 +41,13 @@ config IOAPIC_NUM_RTES config LOAPIC_TIMER_IRQ default 64 +config EOI_FORWARDING_BUG + bool + default y + help + Quark SE LOAPIC has issues with forwarding EOI to the IOAPIC for level + triggered interrupts, this is a SW workaround. + if PINMUX config PINMUX_BASE default 0xB0800930 diff --git a/arch/x86/platforms/quark_se/Makefile b/arch/x86/platforms/quark_se/Makefile index eaaa2f9dca0..11dad612900 100644 --- a/arch/x86/platforms/quark_se/Makefile +++ b/arch/x86/platforms/quark_se/Makefile @@ -4,6 +4,6 @@ ccflags-y +=-I$(srctree)/include/drivers ccflags-y +=-I$(srctree)/drivers asflags-y := ${ccflags-y} -obj-y = system.o quark_se_config.o +obj-y = system.o quark_se_config.o eoi.o obj-$(CONFIG_PINMUX) += pinmux.o obj-$(CONFIG_PINMUX) += curie101_pinmux.o diff --git a/arch/x86/platforms/quark_se/eoi.c b/arch/x86/platforms/quark_se/eoi.c new file mode 100644 index 00000000000..e770feb10f9 --- /dev/null +++ b/arch/x86/platforms/quark_se/eoi.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2015 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * @brief Code to compensate for Lakemont EOI forwarding bug + * + * Lakemont CPU on Quark SE has a bug where LOAPIC EOI does not + * correctly forward EOI to the IOAPIC, causing the IRR bit in the RTE + * to never get cleared. We need to set the IOAPIC EOI register manually + * with the vector of the interrupt. + */ + +#include +#include +#include +#include +#include + +void _lakemont_eoi(void) +{ + int vector = _loapic_isr_vector_get(); + + /* It is difficult to know whether the IRQ being serviced is + * a level interrupt handled by the IOAPIC; the only information + * we have is the vector # in the IDT. So unconditionally + * write to IOAPIC_EOI for every interrupt + */ + sys_write32(vector, CONFIG_IOAPIC_BASE_ADDRESS + IOAPIC_EOI); +} + diff --git a/drivers/interrupt_controller/ioapic_intr.c b/drivers/interrupt_controller/ioapic_intr.c index 0d51f761f73..e241b9339d9 100644 --- a/drivers/interrupt_controller/ioapic_intr.c +++ b/drivers/interrupt_controller/ioapic_intr.c @@ -71,44 +71,7 @@ #include /* public API declarations */ #include /* public API declarations and registers */ - -/* IO APIC direct register offsets */ - -#define IOAPIC_IND 0x00 /* Index Register */ -#define IOAPIC_DATA 0x10 /* IO window (data) - pc.h */ -#define IOAPIC_IRQPA 0x20 /* IRQ Pin Assertion Register */ -#define IOAPIC_EOI 0x40 /* EOI Register */ - -/* IO APIC indirect register offset */ - -#define IOAPIC_ID 0x00 /* IOAPIC ID */ -#define IOAPIC_VERS 0x01 /* IOAPIC Version */ -#define IOAPIC_ARB 0x02 /* IOAPIC Arbitration ID */ -#define IOAPIC_BOOT 0x03 /* IOAPIC Boot Configuration */ -#define IOAPIC_REDTBL 0x10 /* Redirection Table (24 * 64bit) */ - -/* Interrupt delivery type */ - -#define IOAPIC_DT_APIC 0x0 /* APIC serial bus */ -#define IOAPIC_DT_FS 0x1 /* Front side bus message*/ - -/* Version register bits */ - -#define IOAPIC_MRE_MASK 0x00ff0000 /* Max Red. entry mask */ -#define IOAPIC_PRQ 0x00008000 /* this has IRQ reg */ -#define IOAPIC_VERSION 0x000000ff /* version number */ - -/* Redirection table entry number */ - -#define MAX_REDTABLE_ENTRIES 24 - -/* Redirection table entry bits: upper 32 bit */ - -#define IOAPIC_DESTINATION 0xff000000 - -/* Redirection table entry bits: lower 32 bit */ - -#define IOAPIC_VEC_MASK 0x000000ff +#include "ioapic_priv.h" static uint32_t __IoApicGet(int32_t offset); static void __IoApicSet(int32_t offset, uint32_t value); diff --git a/drivers/interrupt_controller/ioapic_priv.h b/drivers/interrupt_controller/ioapic_priv.h new file mode 100644 index 00000000000..649a59efee4 --- /dev/null +++ b/drivers/interrupt_controller/ioapic_priv.h @@ -0,0 +1,61 @@ +/* ioapic_priv.h - private IOAPIC APIs */ + +/* + * Copyright (c) 2012-2015 Wind River Systems, Inc. + * Copyright (c) 2015 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __INCioapic_privh +#define __INCioapic_privh + +/* IO APIC direct register offsets */ + +#define IOAPIC_IND 0x00 /* Index Register */ +#define IOAPIC_DATA 0x10 /* IO window (data) - pc.h */ +#define IOAPIC_IRQPA 0x20 /* IRQ Pin Assertion Register */ +#define IOAPIC_EOI 0x40 /* EOI Register */ + +/* IO APIC indirect register offset */ + +#define IOAPIC_ID 0x00 /* IOAPIC ID */ +#define IOAPIC_VERS 0x01 /* IOAPIC Version */ +#define IOAPIC_ARB 0x02 /* IOAPIC Arbitration ID */ +#define IOAPIC_BOOT 0x03 /* IOAPIC Boot Configuration */ +#define IOAPIC_REDTBL 0x10 /* Redirection Table (24 * 64bit) */ + +/* Interrupt delivery type */ + +#define IOAPIC_DT_APIC 0x0 /* APIC serial bus */ +#define IOAPIC_DT_FS 0x1 /* Front side bus message*/ + +/* Version register bits */ + +#define IOAPIC_MRE_MASK 0x00ff0000 /* Max Red. entry mask */ +#define IOAPIC_PRQ 0x00008000 /* this has IRQ reg */ +#define IOAPIC_VERSION 0x000000ff /* version number */ + +/* Redirection table entry number */ + +#define MAX_REDTABLE_ENTRIES 24 + +/* Redirection table entry bits: upper 32 bit */ + +#define IOAPIC_DESTINATION 0xff000000 + +/* Redirection table entry bits: lower 32 bit */ + +#define IOAPIC_VEC_MASK 0x000000ff + +#endif diff --git a/include/drivers/loapic.h b/include/drivers/loapic.h index 2358e4c465d..a19244ebc7f 100644 --- a/include/drivers/loapic.h +++ b/include/drivers/loapic.h @@ -65,6 +65,9 @@ SECTION_FUNC(TEXT, _\()\device\()_\()\isr\()_stub) pushl \context /* Push context parameter */ call \isr /* Call actual interrupt handler */ popl %eax /* Clean-up stack from push above */ +#if CONFIG_EOI_FORWARDING_BUG + call _lakemont_eoi +#endif xorl %eax, %eax movl %eax, loapic_eoi /* Inform loapic interrupt is done */ jmp _IntExit /* Inform kernel interrupt is done */ @@ -80,6 +83,10 @@ extern void _loapic_enable(void); extern void _loapic_disable(void); extern int _loapic_isr_vector_get(void); +#if CONFIG_EOI_FORWARDING_BUG +extern void _lakemont_eoi(void); +#endif + /** * * @brief send EOI (End Of Interrupt) signal to Local APIC @@ -90,6 +97,9 @@ extern int _loapic_isr_vector_get(void); */ static inline void _loapic_eoi(void) { +#if CONFIG_EOI_FORWARDING_BUG + _lakemont_eoi(); +#endif *(volatile int *)(CONFIG_LOAPIC_BASE_ADDRESS + LOAPIC_EOI) = 0; } #endif /* _ASMLANGUAGE */