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 /core/nds32/task.c | |
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>
Diffstat (limited to 'core/nds32/task.c')
-rw-r--r-- | core/nds32/task.c | 49 |
1 files changed, 38 insertions, 11 deletions
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"); |