drivers: timer: fix tickless contineous interrupts

K_FOREVER/INT_MAX number of ticks needs delay cycles value of
maximum order and exceeds 'int32' range.
The typecast to 'int32' results in wrongly evaluating the value
as less than 'MIN_DELAY' and chooses 'MIN_DELAY' over the actual
delay cycles.

Cap the 'MAX_TICKS' to INT32_MAX.

fixes: #26632
Signed-off-by: Sandeep Tripathy <sandeep.tripathy@broadcom.com>
This commit is contained in:
Sandeep Tripathy 2020-07-03 17:02:20 +05:30 committed by Carles Cufí
commit b37ce93979

View file

@ -10,10 +10,9 @@
#include <spinlock.h>
#include <arch/cpu.h>
#define CYC_PER_TICK ((uint32_t)((uint64_t)sys_clock_hw_cycles_per_sec() \
/ (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC))
#define MAX_TICKS ((0xffffffffu - CYC_PER_TICK) / CYC_PER_TICK)
#define CYC_PER_TICK ((uint64_t)sys_clock_hw_cycles_per_sec() \
/ (uint64_t)CONFIG_SYS_CLOCK_TICKS_PER_SEC)
#define MAX_TICKS INT32_MAX
#define MIN_DELAY (1000)
static struct k_spinlock lock;
@ -33,7 +32,7 @@ static void arm_arch_timer_compare_isr(void *arg)
if (!IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
uint64_t next_cycle = last_cycle + CYC_PER_TICK;
if ((int64_t)(next_cycle - curr_cycle) < MIN_DELAY) {
if ((uint64_t)(next_cycle - curr_cycle) < MIN_DELAY) {
next_cycle += CYC_PER_TICK;
}
arm_arch_timer_set_compare(next_cycle);
@ -67,18 +66,19 @@ void z_clock_set_timeout(int32_t ticks, bool idle)
return;
}
ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : ticks;
ticks = MAX(MIN(ticks - 1, (int32_t)MAX_TICKS), 0);
ticks = (ticks == K_TICKS_FOREVER) ? MAX_TICKS : \
MIN(MAX_TICKS, MAX(ticks - 1, 0));
k_spinlock_key_t key = k_spin_lock(&lock);
uint64_t curr_cycle = arm_arch_timer_count();
uint32_t req_cycle = ticks * CYC_PER_TICK;
uint64_t req_cycle = ticks * CYC_PER_TICK;
/* Round up to next tick boundary */
req_cycle += (uint32_t)(curr_cycle - last_cycle) + (CYC_PER_TICK - 1);
req_cycle += (curr_cycle - last_cycle) + (CYC_PER_TICK - 1);
req_cycle = (req_cycle / CYC_PER_TICK) * CYC_PER_TICK;
if ((int32_t)(req_cycle + last_cycle - curr_cycle) < MIN_DELAY) {
if ((req_cycle + last_cycle - curr_cycle) < MIN_DELAY) {
req_cycle += CYC_PER_TICK;
}
@ -95,8 +95,8 @@ uint32_t z_clock_elapsed(void)
}
k_spinlock_key_t key = k_spin_lock(&lock);
uint32_t ret = ((uint32_t)arm_arch_timer_count() - (uint32_t)last_cycle)
/ CYC_PER_TICK;
uint32_t ret = (uint32_t)((arm_arch_timer_count() - last_cycle)
/ CYC_PER_TICK);
k_spin_unlock(&lock, key);
return ret;