diff options
author | Duncan Laurie <dlaurie@chromium.org> | 2018-03-30 03:17:44 +0000 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2018-03-30 03:22:57 +0000 |
commit | 6dd0b175482f17a5c1af690591d7b05992d1eeff (patch) | |
tree | df8eb4629db4c1bd218f3a1b78cbcdb7f54edc3e | |
parent | 1e45434590362dfc3dcf4fc4d13cf8dc464c0f2f (diff) | |
download | chrome-ec-6dd0b175482f17a5c1af690591d7b05992d1eeff.tar.gz |
npcx: lpc: fixed bug that ec gets stuck in lpc_sib_wait_hostxx routines.
If an ITIM32 timeout event occurred during lpc_sib_wait_host_read_done()
and lpc_sib_wait_host_write_done() routines, in rare case, ec might have
a chance to gets stuck since ec's interrupts are disabled when CSWR/CSRD
bits are high forever. (Normally, CSWR/CSRD bits won't be always high.
These bits are high forever also means something wrong on LPC/eSPI
bus.)
In order to prevent this situation, the CL checks TO_STS bit of ITCTS
in these routines. If this bit is set, restoring ITIM32 preload counter
value to maximum value and processing overflow will be done by
force_time().
BRANCH=eve,fizz,poppy
BUG=b:76182199
TEST=No build errors for npcx series. Passed test command of CL 979389
on npcx_evb. No symptom occurred during warm reset stress test on
soraka.
Original-change-id: Ic645f7c5a2a1e49a3c1f3d7e089dd66b4bb75ac6
Original-signed-off-by: Mulin Chao <mlchao@nuvoton.com>
Change-Id: I3167ed799def4c80cf0bb5544e21ee0f3f0c3133
Signed-off-by: Duncan Laurie <dlaurie@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/987492
Reviewed-by: Duncan Laurie <dlaurie@google.com>
Commit-Queue: Duncan Laurie <dlaurie@google.com>
Tested-by: Duncan Laurie <dlaurie@google.com>
-rw-r--r-- | chip/npcx/hwtimer.c | 18 | ||||
-rw-r--r-- | chip/npcx/hwtimer_chip.h | 3 | ||||
-rw-r--r-- | chip/npcx/lpc.c | 19 |
3 files changed, 34 insertions, 6 deletions
diff --git a/chip/npcx/hwtimer.c b/chip/npcx/hwtimer.c index f12e22e908..d4bb3a15f0 100644 --- a/chip/npcx/hwtimer.c +++ b/chip/npcx/hwtimer.c @@ -267,6 +267,24 @@ void __hw_clock_source_irq(void) } DECLARE_IRQ(NPCX_IRQ_ITIM32, __hw_clock_source_irq, 3); +/* Handle ITIM32 overflow if interrupt is disable */ +void __hw_clock_handle_overflow(uint32_t clksrc_high) +{ + timestamp_t new; + + /* + * Restore ITIM32 preload counter value to maximum and execute + * process_timers() later in ISR by trigger software interrupt in + * force_time(). + */ + new.le.hi = ++clksrc_high; + new.le.lo = 0; + force_time(new); + + /* Clear timeout status */ + SET_BIT(NPCX_ITCTS(ITIM32), NPCX_ITCTS_TO_STS); +} + static void update_prescaler(void) { /* diff --git a/chip/npcx/hwtimer_chip.h b/chip/npcx/hwtimer_chip.h index 08cf8e278f..6e8c7752b2 100644 --- a/chip/npcx/hwtimer_chip.h +++ b/chip/npcx/hwtimer_chip.h @@ -32,4 +32,7 @@ uint16_t __hw_clock_event_count(void); /* Returns time delay because of deep idle */ uint32_t __hw_clock_get_sleep_time(uint16_t pre_evt_cnt); +/* Handle ITIM32 overflow if interrupt is disable */ +void __hw_clock_handle_overflow(uint32_t clksrc_high); + #endif /* __CROS_EC_HWTIMER_CHIP_H */ diff --git a/chip/npcx/lpc.c b/chip/npcx/lpc.c index b649d70ebb..394e72a067 100644 --- a/chip/npcx/lpc.c +++ b/chip/npcx/lpc.c @@ -13,6 +13,7 @@ #include "gpio.h" #include "hooks.h" #include "host_command.h" +#include "hwtimer_chip.h" #include "keyboard_protocol.h" #include "lpc.h" #include "lpc_chip.h" @@ -335,14 +336,17 @@ void lpc_keyboard_put_char(uint8_t chr, int send_irq) */ static void lpc_sib_wait_host_read_done(void) { - timestamp_t deadline; + timestamp_t deadline, start; - deadline.val = get_time().val + LPC_HOST_TRANSACTION_TIMEOUT_US; + start = get_time(); + deadline.val = start.val + LPC_HOST_TRANSACTION_TIMEOUT_US; while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSRD)) { if (timestamp_expired(deadline, NULL)) { ccprintf("Unexpected time of host read transaction\n"); break; - } + } /* Overflow occurred? */ + else if (IS_BIT_SET(NPCX_ITCTS(ITIM32), NPCX_ITCTS_TO_STS)) + __hw_clock_handle_overflow(start.le.hi); } } @@ -351,14 +355,17 @@ static void lpc_sib_wait_host_read_done(void) */ static void lpc_sib_wait_host_write_done(void) { - timestamp_t deadline; + timestamp_t deadline, start; - deadline.val = get_time().val + LPC_HOST_TRANSACTION_TIMEOUT_US; + start = get_time(); + deadline.val = start.val + LPC_HOST_TRANSACTION_TIMEOUT_US; while (IS_BIT_SET(NPCX_SIBCTRL, NPCX_SIBCTRL_CSWR)) { if (timestamp_expired(deadline, NULL)) { ccprintf("Unexpected time of host write transaction\n"); break; - } + } /* Overflow occurred? */ + else if (IS_BIT_SET(NPCX_ITCTS(ITIM32), NPCX_ITCTS_TO_STS)) + __hw_clock_handle_overflow(start.le.hi); } } |