From 88808f1247b6a014f337de42ca458888a4fbb595 Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Thu, 10 Dec 2015 14:43:10 -0800 Subject: [PATCH] quark_se: apic: work around EOI forwarding issue Quark SE Lakemont core has a hardware bug where the LOAPIC does not properly notify the IOAPIC to clear the IRR bit for level- triggered interrupts. This patch introduces a workaround where the vector ID of the in-service interrupt is manually written to the IOAPIC_EOI register, resulting in the bit being cleared. Unfortunately, in the context where EOI happens it's very difficult to identify which IRQ line is being serviced, so this is done unconditionally for all interrupts vectors whether they are registered in the IOAPIC RTE table or not. Change-Id: I639cd258dec4f50934e17eadbb821e6a7112e636 Signed-off-by: Andrew Boie Signed-off-by: Anas Nashif --- arch/x86/platforms/quark_se/Kconfig | 7 +++ arch/x86/platforms/quark_se/Makefile | 2 +- arch/x86/platforms/quark_se/eoi.c | 44 ++++++++++++++++ drivers/interrupt_controller/ioapic_intr.c | 39 +------------- drivers/interrupt_controller/ioapic_priv.h | 61 ++++++++++++++++++++++ include/drivers/loapic.h | 10 ++++ 6 files changed, 124 insertions(+), 39 deletions(-) create mode 100644 arch/x86/platforms/quark_se/eoi.c create mode 100644 drivers/interrupt_controller/ioapic_priv.h 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 */