driver: timer: npcx: fix announce/set timer timeout tick
The timer driver doesn't annouce/set the timeout at the tick boundary but at the absolute next expiration time. It will cause the accumatlation of the tick drift and cannot pass the kernel/timer/timer_behavior test suite. This commit fixes the tick drift problem by annouce the time at the tick bouandry. Fixes #59594 Signed-off-by: Jun Lin <CHLin56@nuvoton.com>
This commit is contained in:
parent
dfc747d53a
commit
4cfd4b5379
|
@ -58,6 +58,7 @@ LOG_MODULE_REGISTER(itim, LOG_LEVEL_ERR);
|
|||
#define NPCX_ITIM_CLK_SEL_DELAY 92 /* Delay for clock selection (Unit:us) */
|
||||
/* Timeout for enabling ITIM module: 100us (Unit:cycles) */
|
||||
#define NPCX_ITIM_EN_TIMEOUT_CYCLES (100 * SYS_CYCLES_PER_USEC)
|
||||
#define SYS_CYC_PER_EVT_CYC (sys_clock_hw_cycles_per_sec() / EVT_CYCLES_PER_SEC)
|
||||
|
||||
/* Instance of system and event timers */
|
||||
static struct itim64_reg *const sys_tmr = (struct itim64_reg *)
|
||||
|
@ -70,6 +71,9 @@ static const struct npcx_clk_cfg itim_clk_cfg[] = NPCX_DT_CLK_CFG_ITEMS_LIST(0);
|
|||
static struct k_spinlock lock;
|
||||
/* Announced cycles in system timer before executing sys_clock_announce() */
|
||||
static uint64_t cyc_sys_announced;
|
||||
static uint64_t last_ticks;
|
||||
static uint32_t last_elapsed;
|
||||
|
||||
/* Current target cycles of time-out signal in event timer */
|
||||
static uint32_t cyc_evt_timeout;
|
||||
/* Total cycles of system timer stopped in "sleep/deep sleep" mode */
|
||||
|
@ -136,18 +140,33 @@ static inline void npcx_itim_evt_disable(void)
|
|||
/* ITIM local functions */
|
||||
static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks)
|
||||
{
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
|
||||
/*
|
||||
* Get desired cycles of event timer from the requested ticks which
|
||||
* round up to next tick boundary.
|
||||
*/
|
||||
|
||||
if (ticks == K_TICKS_FOREVER) {
|
||||
cyc_evt_timeout = NPCX_ITIM32_MAX_CNT;
|
||||
} else {
|
||||
uint64_t next_cycs;
|
||||
uint64_t curr = npcx_itim_get_sys_cyc64();
|
||||
uint32_t dcycles;
|
||||
|
||||
if (ticks <= 0) {
|
||||
ticks = 1;
|
||||
}
|
||||
cyc_evt_timeout = MIN(EVT_CYCLES_FROM_TICKS(ticks),
|
||||
NPCX_ITIM32_MAX_CNT);
|
||||
|
||||
next_cycs = (last_ticks + last_elapsed + ticks) * SYS_CYCLES_PER_TICK;
|
||||
if (unlikely(next_cycs <= curr)) {
|
||||
cyc_evt_timeout = 1;
|
||||
} else {
|
||||
dcycles = next_cycs - curr;
|
||||
cyc_evt_timeout =
|
||||
CLAMP((dcycles / SYS_CYC_PER_EVT_CYC), 1, NPCX_ITIM32_MAX_CNT);
|
||||
}
|
||||
|
||||
}
|
||||
LOG_DBG("ticks %x, cyc_evt_timeout %x", ticks, cyc_evt_timeout);
|
||||
|
||||
|
@ -159,9 +178,9 @@ static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks)
|
|||
/* Upload counter of event timer */
|
||||
evt_tmr->ITCNT32 = MAX(cyc_evt_timeout - 1, 1);
|
||||
|
||||
k_spin_unlock(&lock, key);
|
||||
/* Enable event timer and start ticking */
|
||||
return npcx_itim_evt_enable();
|
||||
|
||||
}
|
||||
|
||||
static void npcx_itim_evt_isr(const struct device *dev)
|
||||
|
@ -175,11 +194,12 @@ static void npcx_itim_evt_isr(const struct device *dev)
|
|||
|
||||
if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
uint32_t delta_ticks = (uint32_t)((npcx_itim_get_sys_cyc64() -
|
||||
cyc_sys_announced) / SYS_CYCLES_PER_TICK);
|
||||
uint64_t curr = npcx_itim_get_sys_cyc64();
|
||||
uint32_t delta_ticks = (uint32_t)((curr - cyc_sys_announced) / SYS_CYCLES_PER_TICK);
|
||||
|
||||
/* Store announced cycles of system timer */
|
||||
cyc_sys_announced = npcx_itim_get_sys_cyc64();
|
||||
cyc_sys_announced += delta_ticks * SYS_CYCLES_PER_TICK;
|
||||
last_ticks += delta_ticks;
|
||||
last_elapsed = 0;
|
||||
k_spin_unlock(&lock, key);
|
||||
|
||||
/* Informs kernel that specified number of ticks have elapsed */
|
||||
|
@ -252,11 +272,13 @@ uint32_t sys_clock_elapsed(void)
|
|||
|
||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||
uint64_t delta_cycle = npcx_itim_get_sys_cyc64() - cyc_sys_announced;
|
||||
uint32_t delta_ticks = (uint32_t)delta_cycle / SYS_CYCLES_PER_TICK;
|
||||
|
||||
last_elapsed = delta_ticks;
|
||||
k_spin_unlock(&lock, key);
|
||||
|
||||
/* Return how many ticks elapsed since last sys_clock_announce() call */
|
||||
return (uint32_t)(delta_cycle / SYS_CYCLES_PER_TICK);
|
||||
return delta_ticks;
|
||||
}
|
||||
|
||||
uint32_t sys_clock_cycle_get_32(void)
|
||||
|
|
Loading…
Reference in a new issue