diff options
author | Dino Li <dino.li@ite.com.tw> | 2016-01-27 13:44:58 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-01-28 00:02:03 -0800 |
commit | a313fc9b1aff224f1229f22dafa7564516eb330c (patch) | |
tree | f3acaed6efa6d3de6c694ae9e1f69f453f5f6c31 | |
parent | 347f516d8444a95e0506640f116e102828b89527 (diff) | |
download | chrome-ec-a313fc9b1aff224f1229f22dafa7564516eb330c.tar.gz |
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>
-rw-r--r-- | chip/it83xx/gpio.c | 3 | ||||
-rw-r--r-- | chip/it83xx/hwtimer.c | 6 | ||||
-rw-r--r-- | chip/it83xx/intc.c | 8 | ||||
-rw-r--r-- | chip/it83xx/intc.h | 1 | ||||
-rw-r--r-- | chip/it83xx/registers.h | 4 | ||||
-rw-r--r-- | chip/it83xx/uart.c | 16 | ||||
-rw-r--r-- | core/nds32/init.S | 39 | ||||
-rw-r--r-- | core/nds32/task.c | 49 |
8 files changed, 88 insertions, 38 deletions
diff --git a/chip/it83xx/gpio.c b/chip/it83xx/gpio.c index fa4d0306f4..cdfa32c9a3 100644 --- a/chip/it83xx/gpio.c +++ b/chip/it83xx/gpio.c @@ -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) { diff --git a/chip/it83xx/hwtimer.c b/chip/it83xx/hwtimer.c index d2ab1d5860..72e9fc7e81 100644 --- a/chip/it83xx/hwtimer.c +++ b/chip/it83xx/hwtimer.c @@ -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(); diff --git a/chip/it83xx/intc.c b/chip/it83xx/intc.c index 37d2f18c35..4bfa1686b7 100644 --- a/chip/it83xx/intc.c +++ b/chip/it83xx/intc.c @@ -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) { diff --git a/chip/it83xx/intc.h b/chip/it83xx/intc.h index 39d8653819..73c69b3c96 100644 --- a/chip/it83xx/intc.h +++ b/chip/it83xx/intc.h @@ -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); diff --git a/chip/it83xx/registers.h b/chip/it83xx/registers.h index 26b8e57323..66c2ace362 100644 --- a/chip/it83xx/registers.h +++ b/chip/it83xx/registers.h @@ -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) diff --git a/chip/it83xx/uart.c b/chip/it83xx/uart.c index 207b6cdb40..69c88e93c7 100644 --- a/chip/it83xx/uart.c +++ b/chip/it83xx/uart.c @@ -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) { diff --git a/core/nds32/init.S b/core/nds32/init.S index 1f9c71b3c6..a1a8bac381 100644 --- a/core/nds32/init.S +++ b/core/nds32/init.S @@ -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 diff --git a/core/nds32/task.c b/core/nds32/task.c index 4be65ac913..1c1053994f 100644 --- a/core/nds32/task.c +++ b/core/nds32/task.c @@ -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 } -void start_irq_handler(void) +/* Interrupt number of EC modules */ +static volatile int ec_int; + +#ifdef CHIP_FAMILY_IT83XX +int intc_get_ec_int(void) { -#ifdef CONFIG_TASK_PROFILING - int irq; + return ec_int; +} #endif + +void start_irq_handler(void) +{ /* 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"); |