diff --git a/arch/arm/src/cxd56xx/cxd56_timer.c b/arch/arm/src/cxd56xx/cxd56_timer.c index 9c93907c9a..43ef8f5885 100644 --- a/arch/arm/src/cxd56xx/cxd56_timer.c +++ b/arch/arm/src/cxd56xx/cxd56_timer.c @@ -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; } diff --git a/drivers/timers/Kconfig b/drivers/timers/Kconfig index b3ffd2cef2..d5416f4969 100644 --- a/drivers/timers/Kconfig +++ b/drivers/timers/Kconfig @@ -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. diff --git a/drivers/timers/arch_timer.c b/drivers/timers/arch_timer.c index 210e703785..4caa2f27a6 100644 --- a/drivers/timers/arch_timer.c +++ b/drivers/timers/arch_timer.c @@ -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; } diff --git a/drivers/timers/timer.c b/drivers/timers/timer.c index 0abcbe0cbc..9dc90e4f7f 100644 --- a/drivers/timers/timer.c +++ b/drivers/timers/timer.c @@ -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 */ diff --git a/include/nuttx/timers/timer.h b/include/nuttx/timers/timer.h index 3b9ba2edea..28ea9e9d0f 100644 --- a/include/nuttx/timers/timer.h +++ b/include/nuttx/timers/timer.h @@ -25,6 +25,7 @@ * Included Files ****************************************************************************/ +#include #include #include #include @@ -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 ****************************************************************************/