summaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorDino Li <dino.li@ite.com.tw>2016-01-27 13:44:58 +0800
committerchrome-bot <chrome-bot@chromium.org>2016-01-28 00:02:03 -0800
commita313fc9b1aff224f1229f22dafa7564516eb330c (patch)
treef3acaed6efa6d3de6c694ae9e1f69f453f5f6c31 /core
parent347f516d8444a95e0506640f116e102828b89527 (diff)
downloadchrome-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>
Diffstat (limited to 'core')
-rw-r--r--core/nds32/init.S39
-rw-r--r--core/nds32/task.c49
2 files changed, 59 insertions, 29 deletions
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");