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) */
|
#define NPCX_ITIM_CLK_SEL_DELAY 92 /* Delay for clock selection (Unit:us) */
|
||||||
/* Timeout for enabling ITIM module: 100us (Unit:cycles) */
|
/* Timeout for enabling ITIM module: 100us (Unit:cycles) */
|
||||||
#define NPCX_ITIM_EN_TIMEOUT_CYCLES (100 * SYS_CYCLES_PER_USEC)
|
#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 */
|
/* Instance of system and event timers */
|
||||||
static struct itim64_reg *const sys_tmr = (struct itim64_reg *)
|
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;
|
static struct k_spinlock lock;
|
||||||
/* Announced cycles in system timer before executing sys_clock_announce() */
|
/* Announced cycles in system timer before executing sys_clock_announce() */
|
||||||
static uint64_t cyc_sys_announced;
|
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 */
|
/* Current target cycles of time-out signal in event timer */
|
||||||
static uint32_t cyc_evt_timeout;
|
static uint32_t cyc_evt_timeout;
|
||||||
/* Total cycles of system timer stopped in "sleep/deep sleep" mode */
|
/* 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 */
|
/* ITIM local functions */
|
||||||
static int npcx_itim_start_evt_tmr_by_tick(int32_t ticks)
|
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
|
* Get desired cycles of event timer from the requested ticks which
|
||||||
* round up to next tick boundary.
|
* round up to next tick boundary.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ticks == K_TICKS_FOREVER) {
|
if (ticks == K_TICKS_FOREVER) {
|
||||||
cyc_evt_timeout = NPCX_ITIM32_MAX_CNT;
|
cyc_evt_timeout = NPCX_ITIM32_MAX_CNT;
|
||||||
} else {
|
} else {
|
||||||
|
uint64_t next_cycs;
|
||||||
|
uint64_t curr = npcx_itim_get_sys_cyc64();
|
||||||
|
uint32_t dcycles;
|
||||||
|
|
||||||
if (ticks <= 0) {
|
if (ticks <= 0) {
|
||||||
ticks = 1;
|
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);
|
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 */
|
/* Upload counter of event timer */
|
||||||
evt_tmr->ITCNT32 = MAX(cyc_evt_timeout - 1, 1);
|
evt_tmr->ITCNT32 = MAX(cyc_evt_timeout - 1, 1);
|
||||||
|
|
||||||
|
k_spin_unlock(&lock, key);
|
||||||
/* Enable event timer and start ticking */
|
/* Enable event timer and start ticking */
|
||||||
return npcx_itim_evt_enable();
|
return npcx_itim_evt_enable();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void npcx_itim_evt_isr(const struct device *dev)
|
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)) {
|
if (IS_ENABLED(CONFIG_TICKLESS_KERNEL)) {
|
||||||
k_spinlock_key_t key = k_spin_lock(&lock);
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||||
uint32_t delta_ticks = (uint32_t)((npcx_itim_get_sys_cyc64() -
|
uint64_t curr = npcx_itim_get_sys_cyc64();
|
||||||
cyc_sys_announced) / SYS_CYCLES_PER_TICK);
|
uint32_t delta_ticks = (uint32_t)((curr - cyc_sys_announced) / SYS_CYCLES_PER_TICK);
|
||||||
|
|
||||||
/* Store announced cycles of system timer */
|
cyc_sys_announced += delta_ticks * SYS_CYCLES_PER_TICK;
|
||||||
cyc_sys_announced = npcx_itim_get_sys_cyc64();
|
last_ticks += delta_ticks;
|
||||||
|
last_elapsed = 0;
|
||||||
k_spin_unlock(&lock, key);
|
k_spin_unlock(&lock, key);
|
||||||
|
|
||||||
/* Informs kernel that specified number of ticks have elapsed */
|
/* 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);
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
||||||
uint64_t delta_cycle = npcx_itim_get_sys_cyc64() - cyc_sys_announced;
|
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);
|
k_spin_unlock(&lock, key);
|
||||||
|
|
||||||
/* Return how many ticks elapsed since last sys_clock_announce() call */
|
/* 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)
|
uint32_t sys_clock_cycle_get_32(void)
|
||||||
|
|
Loading…
Reference in a new issue