Timer Systick : Handle Systick timer rollback in tickless kernel Case

In Tickeless kernel Platform timekeeping is having error because
"_sys_clock_tick_count" is not getting updated correctly.
Currently "OVERFLOW" Flag (bit 16 in timer control register)
is reset before it is taken into account into _sys_clock_tick_count.

This patch sets a flag as soon as Timer Overflow occues and clears
it when time is accounted into _sys_clock_tick_count.

Jira : ZEP-2217

Signed-off-by: Youvedeep Singh <youvedeep.singh@intel.com>
This commit is contained in:
Youvedeep Singh 2017-07-17 13:06:50 +05:30 committed by Anas Nashif
commit 5efaca470c

View file

@ -66,6 +66,9 @@ static u32_t __noinit default_load_value; /* default count */
#ifndef CONFIG_TICKLESS_KERNEL #ifndef CONFIG_TICKLESS_KERNEL
static u32_t idle_original_count; static u32_t idle_original_count;
#endif #endif
#ifdef CONFIG_TICKLESS_KERNEL
static u32_t timer_overflow;
#endif
static u32_t __noinit max_system_ticks; static u32_t __noinit max_system_ticks;
static u32_t idle_original_ticks; static u32_t idle_original_ticks;
static u32_t __noinit max_load_value; static u32_t __noinit max_load_value;
@ -142,7 +145,8 @@ static ALWAYS_INLINE u32_t sysTickCurrentGet(void)
* Counter can rollover if irqs are locked for too long. * Counter can rollover if irqs are locked for too long.
* Return 0 to indicate programmed cycles have expired. * Return 0 to indicate programmed cycles have expired.
*/ */
if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) || (timer_overflow)) {
timer_overflow = 1;
return 0; return 0;
} }
#endif #endif
@ -239,13 +243,13 @@ void _timer_int_handler(void *unused)
#ifdef CONFIG_TICKLESS_IDLE #ifdef CONFIG_TICKLESS_IDLE
#if defined(CONFIG_TICKLESS_KERNEL) #if defined(CONFIG_TICKLESS_KERNEL)
sysTickStop();
if (!idle_original_ticks) { if (!idle_original_ticks) {
if (_sys_clock_always_on) { if (_sys_clock_always_on) {
_sys_clock_tick_count = _get_elapsed_clock_time(); _sys_clock_tick_count = _get_elapsed_clock_time();
/* clear overflow tracking flag as it is accounted */
timer_overflow = 0;
sysTickStop();
idle_original_ticks = max_system_ticks;
sysTickReloadSet(max_load_value); sysTickReloadSet(max_load_value);
sysTickStart(); sysTickStart();
sys_tick_reload(); sys_tick_reload();
@ -272,6 +276,9 @@ void _timer_int_handler(void *unused)
/* _sys_clock_tick_announce() could cause new programming */ /* _sys_clock_tick_announce() could cause new programming */
if (!idle_original_ticks && _sys_clock_always_on) { if (!idle_original_ticks && _sys_clock_always_on) {
_sys_clock_tick_count = _get_elapsed_clock_time(); _sys_clock_tick_count = _get_elapsed_clock_time();
/* clear overflow tracking flag as it is accounted */
timer_overflow = 0;
sysTickStop();
sysTickReloadSet(max_load_value); sysTickReloadSet(max_load_value);
sysTickStart(); sysTickStart();
sys_tick_reload(); sys_tick_reload();
@ -363,7 +370,8 @@ u32_t _get_remaining_program_time(void)
return 0; return 0;
} }
return sysTickCurrentGet() / default_load_value; return (u32_t)ceiling_fraction((u32_t)sysTickCurrentGet(),
default_load_value);
} }
u32_t _get_elapsed_program_time(void) u32_t _get_elapsed_program_time(void)
@ -377,8 +385,6 @@ u32_t _get_elapsed_program_time(void)
void _set_time(u32_t time) void _set_time(u32_t time)
{ {
sysTickStop();
if (!time) { if (!time) {
idle_original_ticks = 0; idle_original_ticks = 0;
return; return;
@ -388,6 +394,9 @@ void _set_time(u32_t time)
_sys_clock_tick_count = _get_elapsed_clock_time(); _sys_clock_tick_count = _get_elapsed_clock_time();
/* clear overflow tracking flag as it is accounted */
timer_overflow = 0;
sysTickStop();
sysTickReloadSet(idle_original_ticks * default_load_value); sysTickReloadSet(idle_original_ticks * default_load_value);
sysTickStart(); sysTickStart();
@ -406,8 +415,12 @@ static inline u64_t get_elapsed_count(void)
{ {
u64_t elapsed; u64_t elapsed;
if (SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) { if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) || (timer_overflow)) {
elapsed = SysTick->LOAD; elapsed = SysTick->LOAD;
/* Keep track of overflow till it is accounted in
* _sys_clock_tick_count as COUNTFLAG bit is clear on read
*/
timer_overflow = 1;
} else { } else {
elapsed = (SysTick->LOAD - SysTick->VAL); elapsed = (SysTick->LOAD - SysTick->VAL);
} }
@ -594,6 +607,8 @@ void _timer_idle_exit(void)
if (idle_mode == IDLE_TICKLESS) { if (idle_mode == IDLE_TICKLESS) {
idle_mode = IDLE_NOT_TICKLESS; idle_mode = IDLE_NOT_TICKLESS;
if (!idle_original_ticks && _sys_clock_always_on) { if (!idle_original_ticks && _sys_clock_always_on) {
_sys_clock_tick_count = _get_elapsed_clock_time();
timer_overflow = 0;
sysTickReloadSet(max_load_value); sysTickReloadSet(max_load_value);
sysTickStart(); sysTickStart();
sys_tick_reload(); sys_tick_reload();