diff options
author | Myles Watson <mylesgw@chromium.org> | 2015-01-09 11:43:33 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-01-14 03:16:18 +0000 |
commit | 16eaf5cfded677cf18c095037c4d35932cdcd274 (patch) | |
tree | 4a45d0c4e6d38628e20198110cdd4799d9bdf69b /chip/nrf51/hwtimer.c | |
parent | 4ee50837a0263a5bfcb61e32a862797ede387c78 (diff) | |
download | chrome-ec-16eaf5cfded677cf18c095037c4d35932cdcd274.tar.gz |
nrf51: Fix a race condition in hwtimer.c
The check for overflow was originally in __hw_clock_source_read()
If it got interrupted, it would frequently see an overflow, because
"prev_read" would be less than "now".
1 - Use the comparator to check for overflow.
2 - Only check for overflow in the interrupt handler.
BUG=chrome-os-partner:35312
BRANCH=none
TEST=make buildall -j
use the keyboard code to type
use a console command "forcetime", to force the system time to overflow soon.
Signed-off-by: Myles Watson <mylesgw@chromium.org>
Change-Id: I7005724222289ba967e89af0ce8b9ef8f90a4ae4
Reviewed-on: https://chromium-review.googlesource.com/239967
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Tested-by: Myles Watson <mylesgw@chromium.org>
Commit-Queue: Myles Watson <mylesgw@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Diffstat (limited to 'chip/nrf51/hwtimer.c')
-rw-r--r-- | chip/nrf51/hwtimer.c | 26 |
1 files changed, 9 insertions, 17 deletions
diff --git a/chip/nrf51/hwtimer.c b/chip/nrf51/hwtimer.c index 79e3cf8b88..281b21211b 100644 --- a/chip/nrf51/hwtimer.c +++ b/chip/nrf51/hwtimer.c @@ -56,8 +56,6 @@ static uint32_t last_deadline; /* cache of event set */ * */ static uint32_t shift; -static uint32_t overflow; -static uint32_t prev_read; void __hw_clock_event_set(uint32_t deadline) { @@ -81,50 +79,44 @@ void __hw_clock_event_clear(void) uint32_t __hw_clock_source_read(void) { - uint32_t now; - /* to capture the current value */ NRF51_TIMER0_CAPTURE1 = 1; - now = NRF51_TIMER0_CC1 + shift; - - /* detect if a wrap happened */ - if (now < prev_read) - overflow++; - prev_read = now; - - return now; + return NRF51_TIMER0_CC1 + shift; } void __hw_clock_source_set(uint32_t ts) { - shift = prev_read = ts; + shift = ts; /* reset counter to zero */ NRF51_TIMER0_STOP = 1; NRF51_TIMER0_CLEAR = 1; - NRF51_TIMER0_START = 1; /* So that no interrupt until next __hw_clock_event_set() */ NRF51_TIMER0_CC0 = ts - 1; /* Update the overflow point */ NRF51_TIMER0_CC2 = 0 - shift; + + /* Start the timer again */ + NRF51_TIMER0_START = 1; } /* Interrupt handler for timer */ void timer_irq(void) { + int overflow = 0; + /* clear status */ NRF51_TIMER0_COMPARE0 = 0; + if (NRF51_TIMER0_COMPARE2) { - /* Invoke a read to update overflow variable */ - __hw_clock_source_read(); NRF51_TIMER0_COMPARE2 = 0; + overflow = 1; } process_timers(overflow); - overflow = 0; } DECLARE_IRQ(NRF51_PERID_TIMER0, timer_irq, 1); |