zephyr/include/drivers/timer/system_timer.h
Andy Ross 7832738ae9 kernel/timeout: Make timeout arguments an opaque type
Add a k_timeout_t type, and use it everywhere that kernel API
functions were accepting a millisecond timeout argument.  Instead of
forcing milliseconds everywhere (which are often not integrally
representable as system ticks), do the conversion to ticks at the
point where the timeout is created.  This avoids an extra unit
conversion in some application code, and allows us to express the
timeout in units other than milliseconds to achieve greater precision.

The existing K_MSEC() et. al. macros now return initializers for a
k_timeout_t.

The K_NO_WAIT and K_FOREVER constants have now become k_timeout_t
values, which means they cannot be operated on as integers.
Applications which have their own APIs that need to inspect these
vs. user-provided timeouts can now use a K_TIMEOUT_EQ() predicate to
test for equality.

Timer drivers, which receive an integer tick count in ther
z_clock_set_timeout() functions, now use the integer-valued
K_TICKS_FOREVER constant instead of K_FOREVER.

For the initial release, to preserve source compatibility, a
CONFIG_LEGACY_TIMEOUT_API kconfig is provided.  When true, the
k_timeout_t will remain a compatible 32 bit value that will work with
any legacy Zephyr application.

Some subsystems present timeout (or timeout-like) values to their own
users as APIs that would re-use the kernel's own constants and
conventions.  These will require some minor design work to adapt to
the new scheme (in most cases just using k_timeout_t directly in their
own API), and they have not been changed in this patch, instead
selecting CONFIG_LEGACY_TIMEOUT_API via kconfig.  These subsystems
include: CAN Bus, the Microbit display driver, I2S, LoRa modem
drivers, the UART Async API, Video hardware drivers, the console
subsystem, and the network buffer abstraction.

k_sleep() now takes a k_timeout_t argument, with a k_msleep() variant
provided that works identically to the original API.

Most of the changes here are just type/configuration management and
documentation, but there are logic changes in mempool, where a loop
that used a timeout numerically has been reworked using a new
z_timeout_end_calc() predicate.  Also in queue.c, a (when POLL was
enabled) a similar loop was needlessly used to try to retry the
k_poll() call after a spurious failure.  But k_poll() does not fail
spuriously, so the loop was removed.

Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
2020-03-31 19:40:47 -04:00

133 lines
4.8 KiB
C

/*
* Copyright (c) 2015 Wind River Systems, Inc.
* Copyright (c) 2019 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief Timer driver API
*
*
* Declare API implemented by system timer driver and used by kernel components.
*/
#ifndef ZEPHYR_INCLUDE_DRIVERS_SYSTEM_TIMER_H_
#define ZEPHYR_INCLUDE_DRIVERS_SYSTEM_TIMER_H_
#include <stdbool.h>
#include <device.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Initialize system clock driver
*
* The system clock is a Zephyr device created globally. This is its
* initialization callback. It is a weak symbol that will be
* implemented as a noop if undefined in the clock driver.
*/
extern int z_clock_driver_init(struct device *device);
/**
* @brief Initialize system clock driver
*
* The system clock is a Zephyr device created globally. This is its
* device control callback, used in a few devices for power
* management. It is a weak symbol that will be implemented as a noop
* if undefined in the clock driver.
*/
extern int z_clock_device_ctrl(struct device *device, u32_t ctrl_command,
void *context, device_pm_cb cb, 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 BEFORE
* the specified expiration (that is, passing ticks==1 means "announce
* the next tick", this convention was chosen to match legacy usage).
* Similarly a ticks value of zero (or even negative) is legal and
* treated identically: it simply indicates the kernel would like the
* next tick announcement as soon as possible.
*
* Note that ticks can also be passed the special value K_TICKS_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 rollover 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.
*
* A final note about SMP: note that the call to z_clock_set_timeout()
* is made on any CPU, and reflects the next timeout desired globally.
* The resulting calls(s) to z_clock_announce() must be properly
* serialized by the driver such that a given tick is announced
* exactly once across the system. The kernel does not (cannot,
* really) attempt to serialize things by "assigning" timeouts to
* specific CPUs.
*
* @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);
/**
* @brief Timer idle exit notification
*
* This notifies the timer driver that the system is exiting the idle
* and allows it to do whatever bookkeeping is needed to restore timer
* operation and compute elapsed ticks.
*
* @note Legacy timer drivers also use this opportunity to call back
* into z_clock_announce() to notify the kernel of expired ticks.
* This is allowed for compatibility, but not recommended. The kernel
* will figure that out on its own.
*/
extern void z_clock_idle_exit(void);
/**
* @brief Announce time progress to the kernel
*
* Informs the kernel that the specified number of ticks have elapsed
* since the last call to z_clock_announce() (or system startup for
* the first call). The timer driver is expected to delivery these
* announcements as close as practical (subject to hardware and
* latency limitations) to tick boundaries.
*
* @param ticks Elapsed time, in ticks
*/
extern void z_clock_announce(s32_t ticks);
/**
* @brief Ticks elapsed since last z_clock_announce() call
*
* Queries the clock driver for the current time elapsed since the
* last call to z_clock_announce() was made. The kernel will call
* this with appropriate locking, the driver needs only provide an
* instantaneous answer.
*/
extern u32_t z_clock_elapsed(void);
#ifdef __cplusplus
}
#endif
#endif /* ZEPHYR_INCLUDE_DRIVERS_SYSTEM_TIMER_H_ */