diff --git a/drivers/timer/altera_avalon_timer_hal.c b/drivers/timer/altera_avalon_timer_hal.c index fcc118c21a6..29d909573cf 100644 --- a/drivers/timer/altera_avalon_timer_hal.c +++ b/drivers/timer/altera_avalon_timer_hal.c @@ -13,6 +13,8 @@ #include "altera_avalon_timer_regs.h" #include "altera_avalon_timer.h" +#include "legacy_api.h" + static u32_t accumulated_cycle_count; static s32_t _sys_idle_elapsed_ticks = 1; diff --git a/drivers/timer/arcv2_timer0.c b/drivers/timer/arcv2_timer0.c index 7a077115642..2c839a44557 100644 --- a/drivers/timer/arcv2_timer0.c +++ b/drivers/timer/arcv2_timer0.c @@ -59,6 +59,8 @@ #include +#include "legacy_api.h" + #define _ARC_V2_TMR_CTRL_IE 0x1 /* interrupt enable */ #define _ARC_V2_TMR_CTRL_NH 0x2 /* count only while not halted */ #define _ARC_V2_TMR_CTRL_W 0x4 /* watchdog mode enable */ diff --git a/drivers/timer/cortex_m_systick.c b/drivers/timer/cortex_m_systick.c index 4f499cdf89a..fea5d8a0218 100644 --- a/drivers/timer/cortex_m_systick.c +++ b/drivers/timer/cortex_m_systick.c @@ -42,6 +42,8 @@ static volatile u32_t clock_accumulated_count; #include +#include "legacy_api.h" + #ifdef CONFIG_TICKLESS_IDLE #define TIMER_MODE_PERIODIC 0 /* normal running mode */ #define TIMER_MODE_ONE_SHOT 1 /* emulated, since sysTick has 1 mode */ diff --git a/drivers/timer/hpet.c b/drivers/timer/hpet.c index dab91ebd9c0..eba56b06aaf 100644 --- a/drivers/timer/hpet.c +++ b/drivers/timer/hpet.c @@ -51,6 +51,8 @@ #include +#include "legacy_api.h" + /* HPET register offsets */ #define GENERAL_CAPS_REG 0 /* 64-bit register */ diff --git a/drivers/timer/legacy_api.h b/drivers/timer/legacy_api.h new file mode 100644 index 00000000000..cefdf1687f4 --- /dev/null +++ b/drivers/timer/legacy_api.h @@ -0,0 +1,32 @@ +#ifndef ZEPHYR_LEGACY_SET_TIME_H__ +#define ZEPHYR_LEGACY_SET_TIME_H__ + +/* Stub implementation of z_clock_set_timeout() in terms of the + * original APIs. Used by older timer drivers. Should be replaced. + * + * Yes, this "header" includes a function definition and must be + * included only once in a single compilation. + */ + + +#ifdef CONFIG_TICKLESS_KERNEL +void _set_time(u32_t time); +#endif + +#ifdef CONFIG_TICKLESS_IDLE +void _timer_idle_enter(s32_t ticks); +void _timer_idle_exit(void); +#endif + +extern void z_clock_set_timeout(s32_t ticks, bool idle) +{ +#ifdef CONFIG_TICKLESS_KERNEL + if (idle) { + _timer_idle_enter(ticks); + } else { + _set_time(ticks == K_FOREVER ? 0 : ticks); + } +#endif +} + +#endif /* ZEPHYR_LEGACY_SET_TIME_H__ */ diff --git a/drivers/timer/loapic_timer.c b/drivers/timer/loapic_timer.c index 3e7b67c0c1b..1dcbf67181b 100644 --- a/drivers/timer/loapic_timer.c +++ b/drivers/timer/loapic_timer.c @@ -76,6 +76,8 @@ #include #include +#include "legacy_api.h" + /* Local APIC Timer Bits */ #define LOAPIC_TIMER_DIVBY_2 0x0 /* Divide by 2 */ diff --git a/drivers/timer/native_posix_timer.c b/drivers/timer/native_posix_timer.c index c03b9f601c8..4598fd19216 100644 --- a/drivers/timer/native_posix_timer.c +++ b/drivers/timer/native_posix_timer.c @@ -20,6 +20,8 @@ #include "soc.h" #include "posix_trace.h" +#include "legacy_api.h" + static u64_t tick_period; /* System tick period in number of hw cycles */ static s64_t silent_ticks; static s32_t _sys_idle_elapsed_ticks = 1; diff --git a/drivers/timer/nrf_rtc_timer.c b/drivers/timer/nrf_rtc_timer.c index d5bfa4fe898..b5e812d0039 100644 --- a/drivers/timer/nrf_rtc_timer.c +++ b/drivers/timer/nrf_rtc_timer.c @@ -11,6 +11,8 @@ #include #include "nrf_rtc.h" +#include "legacy_api.h" + /* * Convenience defines. */ diff --git a/drivers/timer/riscv_machine_timer.c b/drivers/timer/riscv_machine_timer.c index 2f946292f1c..47f4fd1c090 100644 --- a/drivers/timer/riscv_machine_timer.c +++ b/drivers/timer/riscv_machine_timer.c @@ -10,6 +10,8 @@ #include #include +#include "legacy_api.h" + typedef struct { u32_t val_low; u32_t val_high; diff --git a/drivers/timer/xtensa_sys_timer.c b/drivers/timer/xtensa_sys_timer.c index e64beeec874..c3da95e402a 100644 --- a/drivers/timer/xtensa_sys_timer.c +++ b/drivers/timer/xtensa_sys_timer.c @@ -14,6 +14,8 @@ #include "xtensa_rtos.h" +#include "legacy_api.h" + /* * This device driver can be also used with an extenal timer instead of * the internal one that may simply not exist. diff --git a/include/drivers/system_timer.h b/include/drivers/system_timer.h index aa92017b5cb..51a4870608f 100644 --- a/include/drivers/system_timer.h +++ b/include/drivers/system_timer.h @@ -19,6 +19,7 @@ extern "C" { #endif +#include #include #include @@ -26,15 +27,46 @@ extern int _sys_clock_driver_init(struct device *device); extern void _timer_int_handler(void *arg); +/** + * @brief Set system clock timeout + * + * Informs the system clock driver that the next needed call to + * z_clock_announce() will not be until the specified number of ticks + * from the the current time have elapsed. Note that spurious calls + * to z_clock_announce() are allowed (i.e. it's legal to announce + * every tick and implement this function as a noop), the requirement + * is that one tick announcement should occur within one tick after + * the specified expiration. + * + * Note that ticks can also be passed the special value K_FOREVER, + * indicating that no future timer interrupts are expected or required + * and that the system is permitted to enter an indefinite sleep even + * if this could cause rolloever of the internal counter (i.e. the + * system uptime counter is allowed to be wrong, see + * k_enable_sys_clock_always_on(). + * + * Note also that it is conventional for the kernel to pass INT_MAX + * for ticks if it wants to preserve the uptime tick count but doesn't + * have a specific event to await. The intent here is that the driver + * will schedule any needed timeout as far into the future as + * possible. For the specific case of INT_MAX, the next call to + * z_clock_announce() may occur at any point in the future, not just + * at INT_MAX ticks. But the correspondence between the announced + * ticks and real-world time must be correct. + * + * @param ticks Timeout in tick units + * @param idle Hint to the driver that the system is about to enter + * the idle state immediately after setting the timeout + */ +extern void z_clock_set_timeout(s32_t ticks, bool idle); + #ifdef CONFIG_SYSTEM_CLOCK_DISABLE extern void sys_clock_disable(void); #endif #ifdef CONFIG_TICKLESS_IDLE -extern void _timer_idle_enter(s32_t ticks); extern void _timer_idle_exit(void); #else -#define _timer_idle_enter(ticks) do { } while (false) #define _timer_idle_exit() do { } while (false) #endif /* CONFIG_TICKLESS_IDLE */ @@ -50,7 +82,6 @@ extern void _timer_idle_exit(void); extern void z_clock_announce(s32_t ticks); #ifdef CONFIG_TICKLESS_KERNEL -extern void _set_time(u32_t time); extern u32_t _get_program_time(void); extern u32_t _get_remaining_program_time(void); extern u32_t _get_elapsed_program_time(void); diff --git a/kernel/idle.c b/kernel/idle.c index f82a5647db1..a8500f1223f 100644 --- a/kernel/idle.c +++ b/kernel/idle.c @@ -97,7 +97,7 @@ static void sys_power_save_idle(s32_t ticks) * reprogram timer only if the currently programmed time * duration is smaller than the idle time. */ - _timer_idle_enter(ticks); + z_clock_set_timeout(ticks, true); } set_kernel_idle_time_in_ticks(ticks); diff --git a/kernel/include/timeout_q.h b/kernel/include/timeout_q.h index ad6cf0b5e61..e2330ab745a 100644 --- a/kernel/include/timeout_q.h +++ b/kernel/include/timeout_q.h @@ -256,7 +256,7 @@ inserted: #ifdef CONFIG_TICKLESS_KERNEL if (!program_time || (adjusted_timeout < program_time)) { - _set_time(adjusted_timeout); + z_clock_set_timeout(adjusted_timeout, false); } #endif } diff --git a/kernel/sched.c b/kernel/sched.c index a444b998265..dc7b9d28027 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -634,7 +634,7 @@ int _is_thread_time_slicing(struct k_thread *thread) void z_reset_timeslice(void) { if (_is_thread_time_slicing(_get_next_ready_thread())) { - _set_time(_time_slice_duration); + z_clock_set_timeout(_time_slice_duration, false); } } #endif @@ -651,12 +651,12 @@ void _update_time_slice_before_swap(void) u32_t remaining = _get_remaining_program_time(); if (!remaining || (_time_slice_duration < remaining)) { - _set_time(_time_slice_duration); + z_clock_set_timeout(_time_slice_duration, false); } else { /* Account previous elapsed time and reprogram * timer with remaining time */ - _set_time(remaining); + z_clock_set_timeout(remaining, false); } #endif diff --git a/kernel/sys_clock.c b/kernel/sys_clock.c index de0972dbc87..dbad4293ea3 100644 --- a/kernel/sys_clock.c +++ b/kernel/sys_clock.c @@ -323,7 +323,8 @@ void z_clock_announce(s32_t ticks) if ((!remaining && next_to) || (next_to < remaining)) { /* Clears current program if next_to = 0 and remaining > 0 */ - _set_time(next_to); + int dt = next_to ? next_to : (_sys_clock_always_on ? INT_MAX : K_FOREVER); + z_clock_set_timeout(dt, false); } #endif }