arch_timer: adjust timer/arch_timer to support tick
Enable CONFIG_SCHED_TICKLESS_TICK_ARGUMENT in tickless mode to improve the performance.
This commit is contained in:
parent
189aa0292f
commit
b118083c35
@ -72,7 +72,7 @@
|
||||
* wrap around. Timer's base clock is dynamically changed with cpu clock.
|
||||
*/
|
||||
|
||||
#define TIMER_MAXTIMEOUT (ULONG_MAX / 160 / TIMER_DIVIDER)
|
||||
#define CXD56_MAXTIMEOUT (ULONG_MAX / 160 / TIMER_DIVIDER)
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
@ -377,10 +377,10 @@ static int cxd56_settimeout(struct timer_lowerhalf_s *lower,
|
||||
|
||||
/* Can this timeout be represented? */
|
||||
|
||||
if (timeout < 1 || timeout > TIMER_MAXTIMEOUT)
|
||||
if (timeout < 1 || timeout > CXD56_MAXTIMEOUT)
|
||||
{
|
||||
tmrerr("ERROR: Cannot represent timeout=%" PRIu32 " > %lu\n",
|
||||
timeout, TIMER_MAXTIMEOUT);
|
||||
timeout, CXD56_MAXTIMEOUT);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
|
@ -75,6 +75,7 @@ config TIMER_ARCH
|
||||
select ARCH_HAVE_TICKLESS
|
||||
select ARCH_HAVE_TIMEKEEPING
|
||||
select SCHED_TICKLESS_LIMIT_MAX_SLEEP if SCHED_TICKLESS
|
||||
select SCHED_TICKLESS_TICK_ARGUMENT if SCHED_TICKLESS
|
||||
---help---
|
||||
Implement timer arch API on top of timer driver interface.
|
||||
|
||||
|
@ -40,12 +40,6 @@
|
||||
#define CONFIG_BOARD_LOOPSPER10USEC ((CONFIG_BOARD_LOOPSPERMSEC+50)/100)
|
||||
#define CONFIG_BOARD_LOOPSPERUSEC ((CONFIG_BOARD_LOOPSPERMSEC+500)/1000)
|
||||
|
||||
#define TIMER_START(l) ((l)->ops->start(l))
|
||||
#define TIMER_GETSTATUS(l,s) ((l)->ops->getstatus(l,s))
|
||||
#define TIMER_SETTIMEOUT(l,t) ((l)->ops->settimeout(l,t))
|
||||
#define TIMER_SETCALLBACK(l,c,a) ((l)->ops->setcallback(l,c,a))
|
||||
#define TIMER_MAXTIMEOUT(l,t) ((l)->ops->maxtimeout(l,t))
|
||||
|
||||
/****************************************************************************
|
||||
* Private Types
|
||||
****************************************************************************/
|
||||
@ -54,8 +48,7 @@ struct arch_timer_s
|
||||
{
|
||||
FAR struct timer_lowerhalf_s *lower;
|
||||
uint32_t *next_interval;
|
||||
uint32_t maxtimeout;
|
||||
uint64_t timebase;
|
||||
clock_t timebase;
|
||||
};
|
||||
|
||||
/****************************************************************************
|
||||
@ -77,15 +70,6 @@ static inline void timespec_from_usec(FAR struct timespec *ts,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
static inline uint64_t timespec_to_usec(FAR const struct timespec *ts)
|
||||
{
|
||||
return (uint64_t)ts->tv_sec * USEC_PER_SEC + ts->tv_nsec / NSEC_PER_USEC;
|
||||
}
|
||||
|
||||
static inline bool timeout_diff(uint32_t new, uint32_t old)
|
||||
{
|
||||
return new < old ? old - new >= USEC_PER_TICK : new - old >= USEC_PER_TICK;
|
||||
}
|
||||
|
||||
static uint32_t update_timeout(uint32_t timeout)
|
||||
{
|
||||
@ -95,7 +79,7 @@ static uint32_t update_timeout(uint32_t timeout)
|
||||
* since caller already do it for us
|
||||
*/
|
||||
|
||||
TIMER_GETSTATUS(g_timer.lower, &status);
|
||||
TIMER_TICK_GETSTATUS(g_timer.lower, &status);
|
||||
if (g_timer.next_interval)
|
||||
{
|
||||
/* If the timer interrupt is in the process,
|
||||
@ -104,11 +88,11 @@ static uint32_t update_timeout(uint32_t timeout)
|
||||
|
||||
*g_timer.next_interval = timeout;
|
||||
}
|
||||
else if (timeout_diff(timeout, status.timeleft))
|
||||
else if (timeout != status.timeleft)
|
||||
{
|
||||
/* Otherwise, update the timeout directly. */
|
||||
|
||||
TIMER_SETTIMEOUT(g_timer.lower, timeout);
|
||||
TIMER_TICK_SETTIMEOUT(g_timer.lower, timeout);
|
||||
g_timer.timebase += status.timeout - status.timeleft;
|
||||
}
|
||||
|
||||
@ -119,7 +103,7 @@ static uint32_t update_timeout(uint32_t timeout)
|
||||
static uint64_t current_usec(void)
|
||||
{
|
||||
struct timer_status_s status;
|
||||
uint64_t timebase;
|
||||
clock_t timebase;
|
||||
|
||||
do
|
||||
{
|
||||
@ -128,7 +112,7 @@ static uint64_t current_usec(void)
|
||||
}
|
||||
while (timebase != g_timer.timebase);
|
||||
|
||||
return timebase + (status.timeout - status.timeleft);
|
||||
return TICK2USEC(timebase) + (status.timeout - status.timeleft);
|
||||
}
|
||||
|
||||
static void udelay_accurate(useconds_t microseconds)
|
||||
@ -187,27 +171,26 @@ static void udelay_coarse(useconds_t microseconds)
|
||||
}
|
||||
}
|
||||
|
||||
static bool timer_callback(FAR uint32_t *next_interval_us, FAR void *arg)
|
||||
static bool timer_callback(FAR uint32_t *next_interval, FAR void *arg)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
struct timer_status_s status;
|
||||
uint32_t next_interval;
|
||||
uint32_t temp_interval;
|
||||
|
||||
g_timer.timebase += *next_interval_us;
|
||||
next_interval = g_timer.maxtimeout;
|
||||
g_timer.next_interval = &next_interval;
|
||||
g_timer.timebase += *next_interval;
|
||||
temp_interval = g_oneshot_maxticks;
|
||||
g_timer.next_interval = &temp_interval;
|
||||
nxsched_timer_expiration();
|
||||
g_timer.next_interval = NULL;
|
||||
|
||||
TIMER_GETSTATUS(g_timer.lower, &status);
|
||||
if (timeout_diff(next_interval, status.timeleft))
|
||||
TIMER_TICK_GETSTATUS(g_timer.lower, &status);
|
||||
if (temp_interval != status.timeleft)
|
||||
{
|
||||
g_timer.timebase += status.timeout - status.timeleft;
|
||||
*next_interval_us = next_interval;
|
||||
*next_interval = temp_interval;
|
||||
}
|
||||
|
||||
#else
|
||||
g_timer.timebase += USEC_PER_TICK;
|
||||
g_timer.timebase++;
|
||||
nxsched_process_timer();
|
||||
#endif
|
||||
|
||||
@ -222,13 +205,11 @@ void up_timer_set_lowerhalf(FAR struct timer_lowerhalf_s *lower)
|
||||
{
|
||||
g_timer.lower = lower;
|
||||
|
||||
TIMER_MAXTIMEOUT(g_timer.lower, &g_timer.maxtimeout);
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
g_oneshot_maxticks = g_timer.maxtimeout / USEC_PER_TICK;
|
||||
TIMER_SETTIMEOUT(g_timer.lower, g_timer.maxtimeout);
|
||||
g_oneshot_maxticks = TIMER_TICK_MAXTIMEOUT(lower);
|
||||
TIMER_TICK_SETTIMEOUT(g_timer.lower, g_oneshot_maxticks);
|
||||
#else
|
||||
TIMER_SETTIMEOUT(g_timer.lower, USEC_PER_TICK);
|
||||
TIMER_TICK_SETTIMEOUT(g_timer.lower, 1);
|
||||
#endif
|
||||
|
||||
TIMER_SETCALLBACK(g_timer.lower, timer_callback, NULL);
|
||||
@ -271,7 +252,7 @@ void up_timer_set_lowerhalf(FAR struct timer_lowerhalf_s *lower)
|
||||
#ifdef CONFIG_CLOCK_TIMEKEEPING
|
||||
void weak_function up_timer_getmask(FAR clock_t *mask)
|
||||
{
|
||||
uint32_t maxticks = g_timer.maxtimeout / USEC_PER_TICK;
|
||||
uint32_t maxticks = TIMER_TICK_MAXTIMEOUT(g_timer.lower);
|
||||
|
||||
*mask = 0;
|
||||
while (1)
|
||||
@ -287,22 +268,7 @@ void weak_function up_timer_getmask(FAR clock_t *mask)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCHED_TICKLESS) && !defined(CONFIG_SCHED_TICKLESS_TICK_ARGUMENT)
|
||||
int weak_function up_timer_gettime(FAR struct timespec *ts)
|
||||
{
|
||||
int ret = -EAGAIN;
|
||||
|
||||
if (g_timer.lower != NULL)
|
||||
{
|
||||
timespec_from_usec(ts, current_usec());
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SCHED_TICKLESS_TICK_ARGUMENT) || defined(CONFIG_CLOCK_TIMEKEEPING)
|
||||
#if defined(CONFIG_SCHED_TICKLESS) || defined(CONFIG_CLOCK_TIMEKEEPING)
|
||||
int weak_function up_timer_gettick(FAR clock_t *ticks)
|
||||
{
|
||||
int ret = -EAGAIN;
|
||||
@ -354,13 +320,13 @@ int weak_function up_timer_gettick(FAR clock_t *ticks)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int weak_function up_timer_cancel(FAR struct timespec *ts)
|
||||
int weak_function up_timer_tick_cancel(FAR clock_t *ticks)
|
||||
{
|
||||
int ret = -EAGAIN;
|
||||
|
||||
if (g_timer.lower != NULL)
|
||||
{
|
||||
timespec_from_usec(ts, update_timeout(g_timer.maxtimeout));
|
||||
*ticks = update_timeout(g_oneshot_maxticks);
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
@ -394,13 +360,13 @@ int weak_function up_timer_cancel(FAR struct timespec *ts)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_TICKLESS
|
||||
int weak_function up_timer_start(FAR const struct timespec *ts)
|
||||
int weak_function up_timer_tick_start(clock_t ticks)
|
||||
{
|
||||
int ret = -EAGAIN;
|
||||
|
||||
if (g_timer.lower != NULL)
|
||||
{
|
||||
update_timeout(timespec_to_usec(ts));
|
||||
update_timeout(ticks);
|
||||
ret = OK;
|
||||
}
|
||||
|
||||
|
@ -285,14 +285,7 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
/* Start the timer, resetting the time to the current timeout */
|
||||
|
||||
if (lower->ops->start)
|
||||
{
|
||||
ret = lower->ops->start(lower);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
ret = TIMER_START(lower);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -305,8 +298,7 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
/* Stop the timer */
|
||||
|
||||
DEBUGASSERT(lower->ops->stop != NULL); /* Required */
|
||||
ret = lower->ops->stop(lower);
|
||||
ret = TIMER_STOP(lower);
|
||||
nxsig_cancel_notification(&upper->work);
|
||||
}
|
||||
break;
|
||||
@ -322,21 +314,14 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
|
||||
/* Get the current timer status */
|
||||
|
||||
if (lower->ops->getstatus) /* Optional */
|
||||
status = (FAR struct timer_status_s *)((uintptr_t)arg);
|
||||
if (status)
|
||||
{
|
||||
status = (FAR struct timer_status_s *)((uintptr_t)arg);
|
||||
if (status)
|
||||
{
|
||||
ret = lower->ops->getstatus(lower, status);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
ret = TIMER_GETSTATUS(lower, status);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -ENOSYS;
|
||||
ret = -EINVAL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -353,14 +338,7 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
/* Set a new timeout value (and reset the timer) */
|
||||
|
||||
if (lower->ops->settimeout) /* Optional */
|
||||
{
|
||||
ret = lower->ops->settimeout(lower, (uint32_t)arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
ret = TIMER_SETTIMEOUT(lower, (uint32_t)arg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -396,14 +374,7 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
{
|
||||
/* Get the maximum supported timeout value */
|
||||
|
||||
if (lower->ops->maxtimeout) /* Optional */
|
||||
{
|
||||
ret = lower->ops->maxtimeout(lower, (FAR uint32_t *)arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -ENOSYS;
|
||||
}
|
||||
ret = TIMER_MAXTIMEOUT(lower, (FAR uint32_t *)arg);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -420,14 +391,7 @@ static int timer_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
|
||||
* method.
|
||||
*/
|
||||
|
||||
if (lower->ops->ioctl) /* Optional */
|
||||
{
|
||||
ret = lower->ops->ioctl(lower, cmd, arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = -ENOTTY;
|
||||
}
|
||||
ret = TIMER_IOCTL(lower, cmd, arg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -553,8 +517,7 @@ void timer_unregister(FAR void *handle)
|
||||
|
||||
/* Disable the timer */
|
||||
|
||||
DEBUGASSERT(lower->ops->stop); /* Required */
|
||||
lower->ops->stop(lower);
|
||||
TIMER_STOP(lower);
|
||||
nxsig_cancel_notification(&upper->work);
|
||||
|
||||
/* Unregister the timer device */
|
||||
|
@ -25,6 +25,7 @@
|
||||
* Included Files
|
||||
****************************************************************************/
|
||||
|
||||
#include <nuttx/clock.h>
|
||||
#include <nuttx/config.h>
|
||||
#include <nuttx/compiler.h>
|
||||
#include <nuttx/irq.h>
|
||||
@ -88,6 +89,37 @@
|
||||
#define TCFLAGS_HANDLER (1 << 1) /* 1=Call the user function when the
|
||||
* timer expires */
|
||||
|
||||
/* Method access helper macros **********************************************/
|
||||
|
||||
#define TIMER_START(l) \
|
||||
((l)->ops->start ? (l)->ops->start(l) : -ENOSYS)
|
||||
|
||||
#define TIMER_STOP(l) \
|
||||
((l)->ops->stop ? (l)->ops->stop(l) : -ENOSYS)
|
||||
|
||||
#define TIMER_GETSTATUS(l,s) \
|
||||
((l)->ops->getstatus ? (l)->ops->getstatus(l,s) : timer_getstatus(l,s))
|
||||
|
||||
#define TIMER_TICK_GETSTATUS(l,s) \
|
||||
((l)->ops->tick_getstatus ? (l)->ops->tick_getstatus(l,s) : timer_tick_getstatus(l,s))
|
||||
|
||||
#define TIMER_SETTIMEOUT(l,t) \
|
||||
((l)->ops->settimeout ? (l)->ops->settimeout(l,t) : timer_settimeout(l,t))
|
||||
|
||||
#define TIMER_TICK_SETTIMEOUT(l,t) \
|
||||
((l)->ops->tick_setttimeout ? (l)->ops->tick_setttimeout(l,t) : timer_tick_settimeout(l,t))
|
||||
|
||||
#define TIMER_MAXTIMEOUT(l,t) \
|
||||
((l)->ops->maxtimeout ? (l)->ops->maxtimeout(l,t) : timer_maxtimeout(l,t))
|
||||
|
||||
#define TIMER_TICK_MAXTIMEOUT(l,t) \
|
||||
((l)->ops->tick_maxtimeout ? (l)->ops->tick_maxtimeout(l,t) : timer_tick_maxtimeout(l,t))
|
||||
|
||||
#define TIMER_SETCALLBACK(l,c,a) ((l)->ops->setcallback(l,c,a))
|
||||
|
||||
#define TIMER_IOCTL(l,c,a) \
|
||||
((l)->ops->ioctl ? (l)->ops->ioctl(l,c,a) : -ENOTTY)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Types
|
||||
****************************************************************************/
|
||||
@ -96,7 +128,7 @@
|
||||
* function can modify the next interval if desired.
|
||||
*/
|
||||
|
||||
typedef CODE bool (*tccb_t)(FAR uint32_t *next_interval_us, FAR void *arg);
|
||||
typedef CODE bool (*tccb_t)(FAR uint32_t *next_interval, FAR void *arg);
|
||||
|
||||
/* This is the type of the argument passed to the TCIOC_GETSTATUS ioctl and
|
||||
* and returned by the "lower half" getstatus() method.
|
||||
@ -165,6 +197,21 @@ struct timer_ops_s
|
||||
|
||||
CODE int (*maxtimeout)(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR uint32_t *maxtimeout);
|
||||
|
||||
/* Get the current tick timer status */
|
||||
|
||||
CODE int (*tick_getstatus)(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR struct timer_status_s *status);
|
||||
|
||||
/* Set a new tick timeout value of (and reset the timer) */
|
||||
|
||||
CODE int (*tick_setttimeout)(FAR struct timer_lowerhalf_s *lower,
|
||||
uint32_t timeout);
|
||||
|
||||
/* Get the maximum supported tick timeout value */
|
||||
|
||||
CODE int (*tick_maxtimeout)(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR uint32_t *maxtimeout);
|
||||
};
|
||||
|
||||
/* This structure provides the publicly visible representation of the
|
||||
@ -200,6 +247,92 @@ extern "C"
|
||||
#define EXTERN extern
|
||||
#endif
|
||||
|
||||
static inline
|
||||
int timer_getstatus(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR struct timer_status_s *status)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(lower->ops->tick_getstatus);
|
||||
|
||||
ret = lower->ops->tick_getstatus(lower, status);
|
||||
if (ret >= 0)
|
||||
{
|
||||
status->timeout = TICK2USEC(status->timeout);
|
||||
status->timeleft = TICK2USEC(status->timeleft);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline
|
||||
int timer_settimeout(FAR struct timer_lowerhalf_s *lower,
|
||||
uint32_t timeout)
|
||||
{
|
||||
DEBUGASSERT(lower->ops->tick_setttimeout);
|
||||
return lower->ops->tick_setttimeout(lower, USEC2TICK(timeout));
|
||||
}
|
||||
|
||||
static inline
|
||||
int timer_maxtimeout(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR uint32_t *maxtimeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(lower->ops->tick_maxtimeout);
|
||||
|
||||
ret = lower->ops->tick_maxtimeout(lower, maxtimeout);
|
||||
if (ret >= 0)
|
||||
{
|
||||
*maxtimeout = TICK2USEC(*maxtimeout);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline
|
||||
int timer_tick_getstatus(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR struct timer_status_s *status)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(lower->ops->getstatus);
|
||||
|
||||
ret = lower->ops->getstatus(lower, status);
|
||||
if (ret >= 0)
|
||||
{
|
||||
status->timeout = USEC2TICK(status->timeout);
|
||||
status->timeleft = USEC2TICK(status->timeleft);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline
|
||||
int timer_tick_settimeout(FAR struct timer_lowerhalf_s *lower,
|
||||
uint32_t timeout)
|
||||
{
|
||||
DEBUGASSERT(lower->ops->settimeout);
|
||||
return lower->ops->settimeout(lower, TICK2USEC(timeout));
|
||||
}
|
||||
|
||||
static inline
|
||||
int timer_tick_maxtimeout(FAR struct timer_lowerhalf_s *lower,
|
||||
FAR uint32_t *maxtimeout)
|
||||
{
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(lower->ops->maxtimeout);
|
||||
|
||||
ret = lower->ops->maxtimeout(lower, maxtimeout);
|
||||
if (ret >= 0)
|
||||
{
|
||||
*maxtimeout = USEC2TICK(*maxtimeout);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* "Upper-Half" Timer Driver Interfaces
|
||||
****************************************************************************/
|
||||
|
Loading…
Reference in New Issue
Block a user