mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
chip: it83xx: fix EC interrupt vector registers issue
We have a limitation for EC interrupt vector registers. System may read incorrect interrupt number in ISR so we need to add a workaround to prevent it. The following is a example that got incorrect interrupt number: 1. REG IVCTx = 0x10. (no interrupt pending) 2. EC INT6 interrupt occurs (IVCTx = 0x16) and jump to ISR. 3. Read interrupt vector register to determine interrupt number. 4. Higher priority interrupt of same interrupt group occurs (for example: INT134, IVCTx = 0x96) while the system is reading the interrupt vector register for EC INT6, we may end up with an incorrect interrupt number between 0x16 and 0x96. Signed-off-by: Dino Li <dino.li@ite.com.tw> BRANCH=none BUG=none TEST=1. EC interrupts work normally: WUI (GPIO interrupt), timer, uart, LPC, I2C, and PECI. 2. Console command 'taskinfo'. Change-Id: I54e61f417ad506eb3b4cd5d0652f64eed9a28a17 Reviewed-on: https://chromium-review.googlesource.com/322097 Commit-Ready: Dino Li <dino.li@ite.com.tw> Tested-by: Dino Li <dino.li@ite.com.tw> Reviewed-by: Randall Spangler <rspangler@chromium.org>
This commit is contained in:
@@ -9,6 +9,7 @@
|
||||
#include "common.h"
|
||||
#include "gpio.h"
|
||||
#include "hooks.h"
|
||||
#include "intc.h"
|
||||
#include "kmsc_chip.h"
|
||||
#include "registers.h"
|
||||
#include "switch.h"
|
||||
@@ -463,7 +464,7 @@ static void gpio_interrupt(int port, uint8_t mask)
|
||||
static void __gpio_irq(void)
|
||||
{
|
||||
/* Determine interrupt number. */
|
||||
int irq = IT83XX_INTC_IVCT2 - 16;
|
||||
int irq = intc_get_ec_int();
|
||||
|
||||
#if defined(HAS_TASK_KEYSCAN) && defined(CONFIG_IT83XX_KEYBOARD_KSI_WUC_INT)
|
||||
if (irq == IT83XX_IRQ_WKINTC) {
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "hooks.h"
|
||||
#include "hwtimer.h"
|
||||
#include "hwtimer_chip.h"
|
||||
#include "intc.h"
|
||||
#include "irq_chip.h"
|
||||
#include "registers.h"
|
||||
#include "task.h"
|
||||
@@ -167,11 +168,10 @@ int __hw_clock_source_init(uint32_t start_t)
|
||||
static void __hw_clock_source_irq(void)
|
||||
{
|
||||
/* Determine interrupt number. */
|
||||
int irq = IT83XX_INTC_IVCT3 - 16;
|
||||
int irq = intc_get_ec_int();
|
||||
|
||||
/* SW/HW interrupt of event timer. */
|
||||
if ((get_sw_int() == et_ctrl_regs[EVENT_EXT_TIMER].irq) ||
|
||||
(irq == et_ctrl_regs[EVENT_EXT_TIMER].irq)) {
|
||||
if (irq == et_ctrl_regs[EVENT_EXT_TIMER].irq) {
|
||||
IT83XX_ETWD_ETXCNTLR(EVENT_EXT_TIMER) = 0xffffffff;
|
||||
IT83XX_ETWD_ETXCTRL(EVENT_EXT_TIMER) |= (1 << 1);
|
||||
event_timer_clear_pending_isr();
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
void intc_cpu_int_group_5(void)
|
||||
{
|
||||
/* Determine interrupt number. */
|
||||
int intc_group_5 = IT83XX_INTC_IVCT5 - 16;
|
||||
int intc_group_5 = intc_get_ec_int();
|
||||
|
||||
switch (intc_group_5) {
|
||||
#ifdef CONFIG_LPC
|
||||
@@ -38,7 +38,7 @@ DECLARE_IRQ(CPU_INT_GROUP_5, intc_cpu_int_group_5, 2);
|
||||
void intc_cpu_int_group_4(void)
|
||||
{
|
||||
/* Determine interrupt number. */
|
||||
int intc_group_4 = IT83XX_INTC_IVCT4 - 16;
|
||||
int intc_group_4 = intc_get_ec_int();
|
||||
|
||||
switch (intc_group_4) {
|
||||
#ifdef CONFIG_LPC
|
||||
@@ -71,7 +71,7 @@ DECLARE_IRQ(CPU_INT_GROUP_4, intc_cpu_int_group_4, 2);
|
||||
void intc_cpu_int_group_12(void)
|
||||
{
|
||||
/* Determine interrupt number. */
|
||||
int intc_group_12 = IT83XX_INTC_IVCT12 - 16;
|
||||
int intc_group_12 = intc_get_ec_int();
|
||||
|
||||
switch (intc_group_12) {
|
||||
#ifdef CONFIG_PECI
|
||||
@@ -88,7 +88,7 @@ DECLARE_IRQ(CPU_INT_GROUP_12, intc_cpu_int_group_12, 2);
|
||||
void intc_cpu_int_group_6(void)
|
||||
{
|
||||
/* Determine interrupt number. */
|
||||
int intc_group_6 = IT83XX_INTC_IVCT6 - 16;
|
||||
int intc_group_6 = intc_get_ec_int();
|
||||
|
||||
switch (intc_group_6) {
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#ifndef __CROS_EC_INTC_H
|
||||
#define __CROS_EC_INTC_H
|
||||
|
||||
int intc_get_ec_int(void);
|
||||
void lpc_kbc_ibf_interrupt(void);
|
||||
void lpc_kbc_obe_interrupt(void);
|
||||
void pm1_ibf_interrupt(void);
|
||||
|
||||
@@ -311,6 +311,9 @@
|
||||
#define CPU_INT_GROUP_6 250
|
||||
#define IT83XX_CPU_INT_IRQ_250 6
|
||||
|
||||
#define CPU_INT_GROUP_9 249
|
||||
#define IT83XX_CPU_INT_IRQ_249 9
|
||||
|
||||
#define CPU_INT(irq) CONCAT2(IT83XX_CPU_INT_IRQ_, irq)
|
||||
|
||||
/* --- INTC --- */
|
||||
@@ -393,6 +396,7 @@
|
||||
|
||||
#define IT83XX_INTC_EXT_IER_OFF(n) (0x60 + (n))
|
||||
|
||||
#define IT83XX_INTC_IVCT(i) REG8(IT83XX_INTC_BASE+0x80+(i))
|
||||
#define IT83XX_INTC_IVCT0 REG8(IT83XX_INTC_BASE+0x80)
|
||||
#define IT83XX_INTC_IVCT1 REG8(IT83XX_INTC_BASE+0x81)
|
||||
#define IT83XX_INTC_IVCT2 REG8(IT83XX_INTC_BASE+0x82)
|
||||
|
||||
@@ -117,7 +117,21 @@ static void uart_ec_interrupt(void)
|
||||
IT83XX_UART_IER(UART_PORT) = 0;
|
||||
IT83XX_UART_IER(UART_PORT) = uart_ier;
|
||||
}
|
||||
DECLARE_IRQ(IT83XX_IRQ_UART1, uart_ec_interrupt, 1);
|
||||
|
||||
static void intc_cpu_int_group_9(void)
|
||||
{
|
||||
/* Determine interrupt number. */
|
||||
int intc_group_9 = intc_get_ec_int();
|
||||
|
||||
switch (intc_group_9) {
|
||||
case IT83XX_IRQ_UART1:
|
||||
uart_ec_interrupt();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
DECLARE_IRQ(CPU_INT_GROUP_9, intc_cpu_int_group_9, 1);
|
||||
|
||||
static void uart_config(void)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include "config.h"
|
||||
|
||||
/* magic macro to implement IRQ prefix / exit */
|
||||
.macro vector name
|
||||
.macro vector name, entry_number
|
||||
.weak \name\()_handler
|
||||
.set \name\()_handler, unhandled_irq
|
||||
j __entry_\()\name
|
||||
@@ -25,6 +25,9 @@ __entry_\()\name:
|
||||
mov55 $fp, $sp
|
||||
slt45 $r3, $sp /* if sp > end of system stack, then r15 = 1 and */
|
||||
cmovn $sp, $r3, $r15 /* point sp to the top of the system stack */
|
||||
/* save entry number of HW interrupt */
|
||||
movi55 $r3, entry_number
|
||||
swi.gp $r3, [ + cpu_int_entry_number]
|
||||
/* isr entry */
|
||||
jal start_irq_handler
|
||||
/* C routine handler */
|
||||
@@ -58,23 +61,23 @@ j excep_handler /* TLB VLPT miss */
|
||||
j excep_handler /* Machine error */
|
||||
j excep_handler /* Debug related */
|
||||
j excep_handler /* General exception */
|
||||
vector syscall /* Syscall */
|
||||
vector irq_0 /* HW 0 */
|
||||
vector irq_1 /* HW 1 */
|
||||
vector irq_2 /* HW 2 */
|
||||
vector irq_3 /* HW 3 */
|
||||
vector irq_4 /* HW 4 */
|
||||
vector irq_5 /* HW 5 */
|
||||
vector irq_6 /* HW 6 */
|
||||
vector irq_7 /* HW 7 */
|
||||
vector irq_8 /* HW 8 */
|
||||
vector irq_9 /* HW 9 */
|
||||
vector irq_10 /* HW 10 */
|
||||
vector irq_11 /* HW 11 */
|
||||
vector irq_12 /* HW 12 */
|
||||
vector irq_13 /* HW 13 */
|
||||
vector irq_14 /* HW 14 */
|
||||
vector irq_15 /* HW 15 */
|
||||
vector syscall, -1 /* Syscall */
|
||||
vector irq_0, 0 /* HW 0 */
|
||||
vector irq_1, 1 /* HW 1 */
|
||||
vector irq_2, 2 /* HW 2 */
|
||||
vector irq_3, 3 /* HW 3 */
|
||||
vector irq_4, 4 /* HW 4 */
|
||||
vector irq_5, 5 /* HW 5 */
|
||||
vector irq_6, 6 /* HW 6 */
|
||||
vector irq_7, 7 /* HW 7 */
|
||||
vector irq_8, 8 /* HW 8 */
|
||||
vector irq_9, 9 /* HW 9 */
|
||||
vector irq_10, 10 /* HW 10 */
|
||||
vector irq_11, 11 /* HW 11 */
|
||||
vector irq_12, 12 /* HW 12 */
|
||||
vector irq_13, 13 /* HW 13 */
|
||||
vector irq_14, 14 /* HW 14 */
|
||||
vector irq_15, 15 /* HW 15 */
|
||||
|
||||
/* E-flash signature */
|
||||
.org 0x80
|
||||
|
||||
@@ -179,6 +179,9 @@ static int start_called; /* Has task swapping started */
|
||||
/* interrupt number of sw interrupt */
|
||||
static int sw_int_num;
|
||||
|
||||
/* Number of CPU hardware interrupts (HW0 ~ HW15) */
|
||||
int cpu_int_entry_number;
|
||||
|
||||
static inline task_ *__task_id_to_ptr(task_id_t id)
|
||||
{
|
||||
return tasks + id;
|
||||
@@ -340,31 +343,55 @@ void update_exc_start_time(void)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Interrupt number of EC modules */
|
||||
static volatile int ec_int;
|
||||
|
||||
#ifdef CHIP_FAMILY_IT83XX
|
||||
int intc_get_ec_int(void)
|
||||
{
|
||||
return ec_int;
|
||||
}
|
||||
#endif
|
||||
|
||||
void start_irq_handler(void)
|
||||
{
|
||||
#ifdef CONFIG_TASK_PROFILING
|
||||
int irq;
|
||||
#endif
|
||||
/* save r0, r1, and r2 for syscall */
|
||||
asm volatile ("smw.adm $r0, [$sp], $r2, 0");
|
||||
/* If this is a SW interrupt */
|
||||
if (get_itype() & 8) {
|
||||
ec_int = get_sw_int();
|
||||
} else {
|
||||
#ifdef CHIP_FAMILY_IT83XX
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IT83XX_IRQ_COUNT; i++) {
|
||||
ec_int = IT83XX_INTC_IVCT(cpu_int_entry_number);
|
||||
/*
|
||||
* WORKAROUND: when the interrupt vector register isn't
|
||||
* latched in a load operation,
|
||||
* we read it again to make sure the value we got
|
||||
* is the correct value.
|
||||
*/
|
||||
if (ec_int == IT83XX_INTC_IVCT(cpu_int_entry_number))
|
||||
break;
|
||||
}
|
||||
/* Determine interrupt number */
|
||||
ec_int -= 16;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(CONFIG_LOW_POWER_IDLE) && defined(CHIP_FAMILY_IT83XX)
|
||||
clock_sleep_mode_wakeup_isr();
|
||||
#endif
|
||||
#ifdef CONFIG_TASK_PROFILING
|
||||
update_exc_start_time();
|
||||
|
||||
irq = get_sw_int();
|
||||
#ifdef CHIP_FAMILY_IT83XX
|
||||
if (!irq)
|
||||
irq = IT83XX_INTC_AIVCT - 16;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Track IRQ distribution. No need for atomic add, because an IRQ
|
||||
* can't pre-empt itself.
|
||||
*/
|
||||
if ((irq > 0) && (irq < ARRAY_SIZE(irq_dist)))
|
||||
irq_dist[irq]++;
|
||||
if ((ec_int > 0) && (ec_int < ARRAY_SIZE(irq_dist)))
|
||||
irq_dist[ec_int]++;
|
||||
#endif
|
||||
/* restore r0, r1, and r2 */
|
||||
asm volatile ("lmw.bim $r0, [$sp], $r2, 0");
|
||||
|
||||
Reference in New Issue
Block a user