From 88b302d654ba22361b897132b7abe7d7add68e82 Mon Sep 17 00:00:00 2001 From: Matteo Golin Date: Mon, 20 Oct 2025 20:36:05 -0400 Subject: [PATCH] drivers/timers/arch_alarm: Revert removal of ndelay_accurate This reverts the removal of ndelay_accurate from #14450, since as mentioned in #17011, this fails to consider the `sim` architecture where CONFIG_BOARD_LOOPSPERMSEC was set to 0 because of reliance on the accurate implementations of the up_delay functions. All the commit did was remove a more accurate implementation in favour of a less accurate one. Signed-off-by: Matteo Golin --- drivers/timers/arch_alarm.c | 120 ++++++++++++++++++++++++++++++++++++ sched/clock/CMakeLists.txt | 2 +- sched/clock/Make.defs | 4 +- 3 files changed, 124 insertions(+), 2 deletions(-) diff --git a/drivers/timers/arch_alarm.c b/drivers/timers/arch_alarm.c index 35512cada33d4..204a5f3a51aea 100644 --- a/drivers/timers/arch_alarm.c +++ b/drivers/timers/arch_alarm.c @@ -30,6 +30,14 @@ #include #include +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define CONFIG_BOARD_LOOPSPER100USEC ((CONFIG_BOARD_LOOPSPERMSEC+5)/10) +#define CONFIG_BOARD_LOOPSPER10USEC ((CONFIG_BOARD_LOOPSPERMSEC+50)/100) +#define CONFIG_BOARD_LOOPSPERUSEC ((CONFIG_BOARD_LOOPSPERMSEC+500)/1000) + /**************************************************************************** * Private Data ****************************************************************************/ @@ -44,6 +52,69 @@ static clock_t g_current_tick; * Private Functions ****************************************************************************/ +static void udelay_coarse(useconds_t microseconds) +{ + volatile int i; + + /* We'll do this a little at a time because we expect that the + * CONFIG_BOARD_LOOPSPERUSEC is very inaccurate during to truncation in + * the divisions of its calculation. We'll use the largest values that + * we can in order to prevent significant error buildup in the loops. + */ + + while (microseconds > 1000) + { + for (i = 0; i < CONFIG_BOARD_LOOPSPERMSEC; i++) + { + } + + microseconds -= 1000; + } + + while (microseconds > 100) + { + for (i = 0; i < CONFIG_BOARD_LOOPSPER100USEC; i++) + { + } + + microseconds -= 100; + } + + while (microseconds > 10) + { + for (i = 0; i < CONFIG_BOARD_LOOPSPER10USEC; i++) + { + } + + microseconds -= 10; + } + + while (microseconds > 0) + { + for (i = 0; i < CONFIG_BOARD_LOOPSPERUSEC; i++) + { + } + + microseconds--; + } +} + +static void ndelay_accurate(unsigned long nanoseconds) +{ + struct timespec now; + struct timespec end; + struct timespec delta; + + ONESHOT_CURRENT(g_oneshot_lower, &now); + clock_nsec2time(&delta, nanoseconds); + clock_timespec_add(&now, &delta, &end); + + while (clock_timespec_compare(&now, &end) < 0) + { + ONESHOT_CURRENT(g_oneshot_lower, &now); + } +} + static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower, FAR void *arg) { @@ -82,6 +153,55 @@ static void oneshot_callback(FAR struct oneshot_lowerhalf_s *lower, * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: up_mdelay + * + * Description: + * Delay inline for the requested number of milliseconds. + * WARNING: NOT multi-tasking friendly + * + ****************************************************************************/ + +void weak_function up_mdelay(unsigned int milliseconds) +{ + up_udelay(USEC_PER_MSEC * milliseconds); +} + +/**************************************************************************** + * Name: up_udelay + * + * Description: + * Delay inline for the requested number of microseconds. + * WARNING: NOT multi-tasking friendly + * + ****************************************************************************/ + +void weak_function up_udelay(useconds_t microseconds) +{ + up_ndelay(NSEC_PER_USEC * microseconds); +} + +/**************************************************************************** + * Name: up_ndelay + * + * Description: + * Delay inline for the requested number of nanoseconds. + * WARNING: NOT multi-tasking friendly + * + ****************************************************************************/ + +void weak_function up_ndelay(unsigned long nanoseconds) +{ + if (g_oneshot_lower != NULL) + { + ndelay_accurate(nanoseconds); + } + else /* Oneshot timer hasn't been initialized yet */ + { + udelay_coarse((nanoseconds + NSEC_PER_USEC - 1) / NSEC_PER_USEC); + } +} + void up_alarm_set_lowerhalf(FAR struct oneshot_lowerhalf_s *lower) { #ifdef CONFIG_SCHED_TICKLESS diff --git a/sched/clock/CMakeLists.txt b/sched/clock/CMakeLists.txt index c2a12c8b167ce..d440be2cd7b57 100644 --- a/sched/clock/CMakeLists.txt +++ b/sched/clock/CMakeLists.txt @@ -34,7 +34,7 @@ set(SRCS # include the base delay definition (busy-loop) as a minimum-viable product. We # don't want the weak references to conflict. -if(NOT CONFIG_TIMER_ARCH) +if(NOT CONFIG_TIMER_ARCH AND NOT CONFIG_ALARM_ARCH) list(APPEND SRCS delay.c) endif() diff --git a/sched/clock/Make.defs b/sched/clock/Make.defs index f0d281de23b97..ea6e38b58243c 100644 --- a/sched/clock/Make.defs +++ b/sched/clock/Make.defs @@ -29,7 +29,9 @@ CSRCS += clock_perf.c clock_realtime2absticks.c # don't want the weak references to conflict. ifneq ($(CONFIG_TIMER_ARCH),y) - CSRCS += delay.c + ifneq ($(CONFIG_ALARM_ARCH),y) + CSRCS += delay.c + endif endif ifeq ($(CONFIG_CLOCK_TIMEKEEPING),y)