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 <andrew.p.boie@intel.com>
Signed-off-by: Anas Nashif <anas.nashif@intel.com>
This commit is contained in:
Andrew Boie 2015-12-10 14:43:10 -08:00 committed by Anas Nashif
commit 88808f1247
6 changed files with 124 additions and 39 deletions

View file

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

View file

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

View file

@ -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 <nanokernel.h>
#include <drivers/loapic.h>
#include <drivers/ioapic.h>
#include <sys_io.h>
#include <interrupt_controller/ioapic_priv.h>
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);
}

View file

@ -71,44 +71,7 @@
#include <drivers/ioapic.h> /* public API declarations */
#include <drivers/loapic.h> /* 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);

View file

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

View file

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