[PATCH 1/2] arc_timer: fix tickless idle
Desfarges, Simon <simon.desfarges@...>
From: Simon Desfarges <simon.desfarges(a)intel.com>
When exiting from tickless idle uppon an external IRQ, the TICK timer is set to fire at next TICK boundary. The current algorithm can lead to a point that timer0_count register is higher than the timer0_limit register. In this situation the next TICK will fire after a full wrapp of the counter (~133 seconds). This condition appears when the counter reaches the limit after the Interrupt Pending flag is checked. At this point the counter is automatically wrapped to 0, but is set just next the limit to fire at next TICK boundary by SW. At exit of the _timer_idle_exit function, the timer handler is called, and sets the limit to 1 TICK. At this point the situation is: - limit register == 1 TICK - count register is just below the old limit register and higher than 1 TICK To fix this issue, at _timer_idle_exit, the limit register is always set to 1 TICK and the count register set such as the next TICK fires on time. Change-Id: Ifa002809d426aa04109592e53d2b02a224f51101 Tracked-On: https://jira.ndg.intel.com/browse/FIRE-4213 Signed-off-by: Simon Desfarges <simon.desfarges(a)intel.com> --- drivers/timer/arcv2_timer0.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/timer/arcv2_timer0.c b/drivers/timer/arcv2_timer0.c index 932ceac..5fec988 100644 --- a/drivers/timer/arcv2_timer0.c +++ b/drivers/timer/arcv2_timer0.c @@ -220,7 +220,7 @@ void _timer_idle_enter(int32_t ticks) } programmed_ticks = ticks; - programmed_limit = (programmed_ticks * cycles_per_tick); + programmed_limit = (programmed_ticks * cycles_per_tick) - 1; timer0_limit_register_set(programmed_limit); @@ -276,9 +276,6 @@ void _timer_idle_exit(void) * A non-timer interrupt occurred. Announce any * ticks that have elapsed during the tickless idle. */ - - uint32_t remaining_cycles = programmed_limit - current_count; - _sys_idle_elapsed_ticks = current_count / cycles_per_tick; if (_sys_idle_elapsed_ticks > 0) { update_accumulated_count(); @@ -289,11 +286,8 @@ void _timer_idle_exit(void) * Ensure the timer will expire at the end of the next tick in case * the ISR makes any tasks and/or fibers ready to run. */ - - if (remaining_cycles >= cycles_per_tick) { - timer0_count_register_set(programmed_limit - - ((remaining_cycles - 1) % cycles_per_tick) - 1); - } + timer0_limit_register_set(cycles_per_tick - 1); + timer0_count_register_set(timer0_count_register_get() % cycles_per_tick); } #else static void tickless_idle_init(void) {} -- 1.9.1 |
|