From fd49cf7d02914669df8d86b67a1c7f1a0de76a52 Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Tue, 21 May 2019 14:02:26 -0700 Subject: [PATCH] kernel: timeout: add syscall for runtime clk freq If the system sets its clock frequency at runtime, this is stored in a variable that can't be directly read by user mode. For this case only, add a system call to fetch its value and modify the definition of sys_clock_hw_cycles_per_sec() to use it. Since this is now a system call, store in a temporary variable inside z_ms_to_ticks(). The syscall overhead only applies when called from user mode, other contexts are completely inlined. Added stub syscall header for mocking framework, to get rid of inclusion errors. Fixes: #16238 Signed-off-by: Andrew Boie --- include/sys_clock.h | 23 ++++++++++++++----- kernel/timeout.c | 9 +++++++- .../ztest/include/syscalls/sys_clock.h | 3 +++ 3 files changed, 28 insertions(+), 7 deletions(-) create mode 100644 subsys/testsuite/ztest/include/syscalls/sys_clock.h diff --git a/include/sys_clock.h b/include/sys_clock.h index 87b71753df8..60df21ab2be 100644 --- a/include/sys_clock.h +++ b/include/sys_clock.h @@ -31,12 +31,21 @@ extern int _sys_clock_always_on; extern void z_enable_sys_clock(void); #endif -static inline int sys_clock_hw_cycles_per_sec(void) -{ #if defined(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) +__syscall int z_clock_hw_cycles_per_sec_runtime_get(void); + +static inline int z_impl_z_clock_hw_cycles_per_sec_runtime_get(void) +{ extern int z_clock_hw_cycles_per_sec; return z_clock_hw_cycles_per_sec; +} +#endif /* CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME */ + +static inline int sys_clock_hw_cycles_per_sec(void) +{ +#if defined(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) + return z_clock_hw_cycles_per_sec_runtime_get(); #else return CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; #endif @@ -100,11 +109,11 @@ static ALWAYS_INLINE s32_t z_ms_to_ticks(s32_t ms) #ifdef CONFIG_SYS_CLOCK_EXISTS #ifdef _NEED_PRECISE_TICK_MS_CONVERSION + int cyc = sys_clock_hw_cycles_per_sec(); + /* use 64-bit math to keep precision */ - return (s32_t)ceiling_fraction( - (s64_t)ms * sys_clock_hw_cycles_per_sec(), - ((s64_t)MSEC_PER_SEC * sys_clock_hw_cycles_per_sec()) / - CONFIG_SYS_CLOCK_TICKS_PER_SEC); + return (s32_t)ceiling_fraction((s64_t)ms * cyc, + ((s64_t)MSEC_PER_SEC * cyc) / CONFIG_SYS_CLOCK_TICKS_PER_SEC); #else /* simple division keeps precision */ s32_t ms_per_tick = MSEC_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC; @@ -234,4 +243,6 @@ struct _timeout { } #endif +#include + #endif /* ZEPHYR_INCLUDE_SYS_CLOCK_H_ */ diff --git a/kernel/timeout.c b/kernel/timeout.c index a24f0b4b6e4..f3beba4fcda 100644 --- a/kernel/timeout.c +++ b/kernel/timeout.c @@ -28,7 +28,14 @@ static int announce_remaining; #if defined(CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME) int z_clock_hw_cycles_per_sec = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC; -#endif + +#ifdef CONFIG_USERSPACE +Z_SYSCALL_HANDLER(z_clock_hw_cycles_per_sec_runtime_get) +{ + return z_impl_z_clock_hw_cycles_per_sec_runtime_get(); +} +#endif /* CONFIG_USERSPACE */ +#endif /* CONFIG_TIMER_READS_ITS_FREQUENCY_AT_RUNTIME */ static struct _timeout *first(void) { diff --git a/subsys/testsuite/ztest/include/syscalls/sys_clock.h b/subsys/testsuite/ztest/include/syscalls/sys_clock.h new file mode 100644 index 00000000000..1cfdde31e13 --- /dev/null +++ b/subsys/testsuite/ztest/include/syscalls/sys_clock.h @@ -0,0 +1,3 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + */