drivers/timer: Unify timeout setting APIs
The existing API had two almost identical functions: _set_time() and _timer_idle_enter(). Both simply instruct the timer driver to set the next timer interrupt expiration appropriately so that the call to z_clock_announce() will be made at the requested number of ticks. On most/all hardware, these should be implementable identically. Unfortunately because they are specified differently, existing drivers have implemented them in parallel. Specify a new, unified, z_clock_set_timeout(). Document it clearly for implementors. And provide a shim layer for legacy drivers that will continue to use the old functions. Note that this patch fixes an existing bug found by inspection: the old call to _set_time() out of z_clock_announce() failed to test for the "wait forever" case in the situation where clock_always_on is true, meaning that a system that reached this point and then never set another timeout would freeze its uptime clock incorrectly. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
parent
fa99ad66d0
commit
ab488277bc
15 changed files with 91 additions and 9 deletions
|
@ -13,6 +13,8 @@
|
||||||
#include "altera_avalon_timer_regs.h"
|
#include "altera_avalon_timer_regs.h"
|
||||||
#include "altera_avalon_timer.h"
|
#include "altera_avalon_timer.h"
|
||||||
|
|
||||||
|
#include "legacy_api.h"
|
||||||
|
|
||||||
static u32_t accumulated_cycle_count;
|
static u32_t accumulated_cycle_count;
|
||||||
|
|
||||||
static s32_t _sys_idle_elapsed_ticks = 1;
|
static s32_t _sys_idle_elapsed_ticks = 1;
|
||||||
|
|
|
@ -59,6 +59,8 @@
|
||||||
|
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
|
|
||||||
|
#include "legacy_api.h"
|
||||||
|
|
||||||
#define _ARC_V2_TMR_CTRL_IE 0x1 /* interrupt enable */
|
#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_NH 0x2 /* count only while not halted */
|
||||||
#define _ARC_V2_TMR_CTRL_W 0x4 /* watchdog mode enable */
|
#define _ARC_V2_TMR_CTRL_W 0x4 /* watchdog mode enable */
|
||||||
|
|
|
@ -42,6 +42,8 @@ static volatile u32_t clock_accumulated_count;
|
||||||
|
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
|
|
||||||
|
#include "legacy_api.h"
|
||||||
|
|
||||||
#ifdef CONFIG_TICKLESS_IDLE
|
#ifdef CONFIG_TICKLESS_IDLE
|
||||||
#define TIMER_MODE_PERIODIC 0 /* normal running mode */
|
#define TIMER_MODE_PERIODIC 0 /* normal running mode */
|
||||||
#define TIMER_MODE_ONE_SHOT 1 /* emulated, since sysTick has 1 mode */
|
#define TIMER_MODE_ONE_SHOT 1 /* emulated, since sysTick has 1 mode */
|
||||||
|
|
|
@ -51,6 +51,8 @@
|
||||||
|
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
|
|
||||||
|
#include "legacy_api.h"
|
||||||
|
|
||||||
/* HPET register offsets */
|
/* HPET register offsets */
|
||||||
|
|
||||||
#define GENERAL_CAPS_REG 0 /* 64-bit register */
|
#define GENERAL_CAPS_REG 0 /* 64-bit register */
|
||||||
|
|
32
drivers/timer/legacy_api.h
Normal file
32
drivers/timer/legacy_api.h
Normal file
|
@ -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__ */
|
|
@ -76,6 +76,8 @@
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
#include <kernel_structs.h>
|
#include <kernel_structs.h>
|
||||||
|
|
||||||
|
#include "legacy_api.h"
|
||||||
|
|
||||||
/* Local APIC Timer Bits */
|
/* Local APIC Timer Bits */
|
||||||
|
|
||||||
#define LOAPIC_TIMER_DIVBY_2 0x0 /* Divide by 2 */
|
#define LOAPIC_TIMER_DIVBY_2 0x0 /* Divide by 2 */
|
||||||
|
|
|
@ -20,6 +20,8 @@
|
||||||
#include "soc.h"
|
#include "soc.h"
|
||||||
#include "posix_trace.h"
|
#include "posix_trace.h"
|
||||||
|
|
||||||
|
#include "legacy_api.h"
|
||||||
|
|
||||||
static u64_t tick_period; /* System tick period in number of hw cycles */
|
static u64_t tick_period; /* System tick period in number of hw cycles */
|
||||||
static s64_t silent_ticks;
|
static s64_t silent_ticks;
|
||||||
static s32_t _sys_idle_elapsed_ticks = 1;
|
static s32_t _sys_idle_elapsed_ticks = 1;
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
#include <sys_clock.h>
|
#include <sys_clock.h>
|
||||||
#include "nrf_rtc.h"
|
#include "nrf_rtc.h"
|
||||||
|
|
||||||
|
#include "legacy_api.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convenience defines.
|
* Convenience defines.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include <system_timer.h>
|
#include <system_timer.h>
|
||||||
#include <board.h>
|
#include <board.h>
|
||||||
|
|
||||||
|
#include "legacy_api.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
u32_t val_low;
|
u32_t val_low;
|
||||||
u32_t val_high;
|
u32_t val_high;
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
|
|
||||||
#include "xtensa_rtos.h"
|
#include "xtensa_rtos.h"
|
||||||
|
|
||||||
|
#include "legacy_api.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This device driver can be also used with an extenal timer instead of
|
* This device driver can be also used with an extenal timer instead of
|
||||||
* the internal one that may simply not exist.
|
* the internal one that may simply not exist.
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <device.h>
|
#include <device.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
@ -26,15 +27,46 @@ extern int _sys_clock_driver_init(struct device *device);
|
||||||
|
|
||||||
extern void _timer_int_handler(void *arg);
|
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
|
#ifdef CONFIG_SYSTEM_CLOCK_DISABLE
|
||||||
extern void sys_clock_disable(void);
|
extern void sys_clock_disable(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_TICKLESS_IDLE
|
#ifdef CONFIG_TICKLESS_IDLE
|
||||||
extern void _timer_idle_enter(s32_t ticks);
|
|
||||||
extern void _timer_idle_exit(void);
|
extern void _timer_idle_exit(void);
|
||||||
#else
|
#else
|
||||||
#define _timer_idle_enter(ticks) do { } while (false)
|
|
||||||
#define _timer_idle_exit() do { } while (false)
|
#define _timer_idle_exit() do { } while (false)
|
||||||
#endif /* CONFIG_TICKLESS_IDLE */
|
#endif /* CONFIG_TICKLESS_IDLE */
|
||||||
|
|
||||||
|
@ -50,7 +82,6 @@ extern void _timer_idle_exit(void);
|
||||||
extern void z_clock_announce(s32_t ticks);
|
extern void z_clock_announce(s32_t ticks);
|
||||||
|
|
||||||
#ifdef CONFIG_TICKLESS_KERNEL
|
#ifdef CONFIG_TICKLESS_KERNEL
|
||||||
extern void _set_time(u32_t time);
|
|
||||||
extern u32_t _get_program_time(void);
|
extern u32_t _get_program_time(void);
|
||||||
extern u32_t _get_remaining_program_time(void);
|
extern u32_t _get_remaining_program_time(void);
|
||||||
extern u32_t _get_elapsed_program_time(void);
|
extern u32_t _get_elapsed_program_time(void);
|
||||||
|
|
|
@ -97,7 +97,7 @@ static void sys_power_save_idle(s32_t ticks)
|
||||||
* reprogram timer only if the currently programmed time
|
* reprogram timer only if the currently programmed time
|
||||||
* duration is smaller than the idle 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);
|
set_kernel_idle_time_in_ticks(ticks);
|
||||||
|
|
|
@ -256,7 +256,7 @@ inserted:
|
||||||
|
|
||||||
#ifdef CONFIG_TICKLESS_KERNEL
|
#ifdef CONFIG_TICKLESS_KERNEL
|
||||||
if (!program_time || (adjusted_timeout < program_time)) {
|
if (!program_time || (adjusted_timeout < program_time)) {
|
||||||
_set_time(adjusted_timeout);
|
z_clock_set_timeout(adjusted_timeout, false);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -634,7 +634,7 @@ int _is_thread_time_slicing(struct k_thread *thread)
|
||||||
void z_reset_timeslice(void)
|
void z_reset_timeslice(void)
|
||||||
{
|
{
|
||||||
if (_is_thread_time_slicing(_get_next_ready_thread())) {
|
if (_is_thread_time_slicing(_get_next_ready_thread())) {
|
||||||
_set_time(_time_slice_duration);
|
z_clock_set_timeout(_time_slice_duration, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -651,12 +651,12 @@ void _update_time_slice_before_swap(void)
|
||||||
u32_t remaining = _get_remaining_program_time();
|
u32_t remaining = _get_remaining_program_time();
|
||||||
|
|
||||||
if (!remaining || (_time_slice_duration < remaining)) {
|
if (!remaining || (_time_slice_duration < remaining)) {
|
||||||
_set_time(_time_slice_duration);
|
z_clock_set_timeout(_time_slice_duration, false);
|
||||||
} else {
|
} else {
|
||||||
/* Account previous elapsed time and reprogram
|
/* Account previous elapsed time and reprogram
|
||||||
* timer with remaining time
|
* timer with remaining time
|
||||||
*/
|
*/
|
||||||
_set_time(remaining);
|
z_clock_set_timeout(remaining, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -323,7 +323,8 @@ void z_clock_announce(s32_t ticks)
|
||||||
|
|
||||||
if ((!remaining && next_to) || (next_to < remaining)) {
|
if ((!remaining && next_to) || (next_to < remaining)) {
|
||||||
/* Clears current program if next_to = 0 and remaining > 0 */
|
/* 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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue