diff --git a/doc/reference/kernel/timing/clocks.rst b/doc/reference/kernel/timing/clocks.rst index e1697752a71..4f0b7a9328e 100644 --- a/doc/reference/kernel/timing/clocks.rst +++ b/doc/reference/kernel/timing/clocks.rst @@ -19,8 +19,8 @@ the advantages of being universally portable and pervasively understood, though they may not match the precision of the underlying hardware perfectly. -The kernel presents a "cycle" count via the -:c:func:`k_cycle_get_32` API. The intent is that this counter +The kernel presents a "cycle" count via the :c:func:`k_cycle_get_32` +and :c:func:`k_cycle_get_64` APIs. The intent is that this counter represents the fastest cycle counter that the operating system is able to present to the user (for example, a CPU cycle counter) and that the read operation is very fast. The expectation is that very sensitive diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig index 864bea68323..970531cc4d0 100644 --- a/drivers/timer/Kconfig +++ b/drivers/timer/Kconfig @@ -7,6 +7,12 @@ menu "Timer Drivers" +config TIMER_HAS_64BIT_CYCLE_COUNTER + bool + help + When this option is true, the k_cycle_get_64() call is + available to provide values from a 64-bit cycle counter. + menuconfig APIC_TIMER bool "New local APIC timer" depends on X86 @@ -34,6 +40,7 @@ config APIC_TIMER_IRQ config APIC_TIMER_TSC bool "Use invariant TSC for sys_clock_cycle_get_32()" + select TIMER_HAS_64BIT_CYCLE_COUNTER help If your CPU supports invariant TSC, and you know the ratio of the TSC frequency to CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC (the local APIC @@ -84,6 +91,7 @@ config HPET_TIMER select LOAPIC if X86 imply TIMER_READS_ITS_FREQUENCY_AT_RUNTIME select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER help This option selects High Precision Event Timer (HPET) as a system timer. @@ -110,6 +118,7 @@ config ARM_ARCH_TIMER depends on GIC select ARCH_HAS_CUSTOM_BUSY_WAIT select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER help This module implements a kernel device driver for the ARM architected timer which provides per-cpu timers attached to a GIC to deliver its @@ -220,6 +229,7 @@ config RISCV_MACHINE_TIMER bool "RISCV Machine Timer" depends on SOC_FAMILY_RISCV_PRIVILEGE select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER help This module implements a kernel device driver for the generic RISCV machine timer driver. It provides the standard "system clock driver" interfaces. @@ -238,6 +248,7 @@ config LITEX_TIMER bool "LiteX Timer" default y depends on SOC_RISCV32_LITEX_VEXRISCV + select TIMER_HAS_64BIT_CYCLE_COUNTER help This module implements a kernel device driver for LiteX Timer. @@ -246,6 +257,7 @@ config NATIVE_POSIX_TIMER default y depends on BOARD_NATIVE_POSIX select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER help This module implements a kernel device driver for the native_posix HW timer model @@ -264,6 +276,7 @@ config ESP32C3_SYS_TIMER depends on SOC_ESP32C3 default y select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER help This option enables the system timer driver for the Espressif ESP32C3 and provides the standard "system clock driver" interface. @@ -303,6 +316,7 @@ config CC13X2_CC26X2_RTC_TIMER bool "TI SimpleLink CC13x2/CC26x2 RTC timer" depends on SOC_SERIES_CC13X2_CC26X2 select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER help This module implements a kernel device driver for the TI SimpleLink CC13X2_CC26X2 series Real Time Counter and provides the standard @@ -339,6 +353,7 @@ config CAVS_TIMER bool "CAVS DSP Wall Clock Timer on Intel SoC" depends on CAVS_ICTL select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER help The DSP wall clock timer is a timer driven directly by external oscillator and is external to the CPU core(s). @@ -359,6 +374,7 @@ config NPCX_ITIM_TIMER default y depends on SOC_FAMILY_NPCX select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER help This module implements a kernel device driver for the Nuvoton NPCX series internal 64/32-bit timers and provides the standard "system @@ -413,6 +429,7 @@ config MCUX_OS_TIMER depends on HAS_MCUX_OS_TIMER default $(dt_compat_enabled,$(DT_COMPAT_NXP_OS_TIMER)) select TICKLESS_CAPABLE + select TIMER_HAS_64BIT_CYCLE_COUNTER help This module implements a kernel device driver for the NXP OS event timer and provides the standard "system clock driver" interfaces. diff --git a/drivers/timer/apic_tsc.c b/drivers/timer/apic_tsc.c index c35c868acba..24453ab0c9e 100644 --- a/drivers/timer/apic_tsc.c +++ b/drivers/timer/apic_tsc.c @@ -97,6 +97,11 @@ uint32_t sys_clock_cycle_get_32(void) return (uint32_t) rdtsc(); } +uint64_t sys_clock_cycle_get_64(void) +{ + return rdtsc(); +} + static inline uint32_t timer_irq(void) { /* The Zephyr APIC API is... idiosyncratic. The timer is a diff --git a/drivers/timer/arm_arch_timer.c b/drivers/timer/arm_arch_timer.c index b2ceae45025..4e6891b8f69 100644 --- a/drivers/timer/arm_arch_timer.c +++ b/drivers/timer/arm_arch_timer.c @@ -153,6 +153,11 @@ uint32_t sys_clock_cycle_get_32(void) return (uint32_t)arm_arch_timer_count(); } +uint64_t sys_clock_cycle_get_64(void) +{ + return arm_arch_timer_count(); +} + #ifdef CONFIG_ARCH_HAS_CUSTOM_BUSY_WAIT void arch_busy_wait(uint32_t usec_to_wait) { diff --git a/drivers/timer/cavs_timer.c b/drivers/timer/cavs_timer.c index b10b499b72b..3c2f2519bf6 100644 --- a/drivers/timer/cavs_timer.c +++ b/drivers/timer/cavs_timer.c @@ -77,6 +77,17 @@ static uint32_t count32(void) return shim_regs->walclk32_lo; } +static uint64_t count64(void) +{ + k_spinlock_key_t key = k_spin_lock(&lock); + uint64_t ret = shim_regs->walclk32_lo; + + ret |= (uint64_t)shim_regs->walclk32_hi << 32; + + k_spin_unlock(&lock, key); + return ret; +} + static void compare_isr(const void *arg) { ARG_UNUSED(arg); @@ -182,6 +193,11 @@ uint32_t sys_clock_cycle_get_32(void) return count32(); } +uint64_t sys_clock_cycle_get_64(void) +{ + return count64(); +} + /* Runs on secondary cores */ void smp_timer_init(void) { diff --git a/drivers/timer/cc13x2_cc26x2_rtc_timer.c b/drivers/timer/cc13x2_cc26x2_rtc_timer.c index 8ed92bbd153..7950d5be296 100644 --- a/drivers/timer/cc13x2_cc26x2_rtc_timer.c +++ b/drivers/timer/cc13x2_cc26x2_rtc_timer.c @@ -240,6 +240,10 @@ uint32_t sys_clock_elapsed(void) uint32_t sys_clock_cycle_get_32(void) { - return (AONRTCCurrent64BitValueGet() / RTC_COUNTS_PER_CYCLE) - & 0xFFFFFFFF; + return (uint32_t)(AONRTCCurrent64BitValueGet() / RTC_COUNTS_PER_CYCLE); +} + +uint64_t sys_clock_cycle_get_64(void) +{ + return AONRTCCurrent64BitValueGet() / RTC_COUNTS_PER_CYCLE; } diff --git a/drivers/timer/esp32c3_sys_timer.c b/drivers/timer/esp32c3_sys_timer.c index ebeeb9c0be7..bfa16b253c4 100644 --- a/drivers/timer/esp32c3_sys_timer.c +++ b/drivers/timer/esp32c3_sys_timer.c @@ -134,3 +134,15 @@ uint32_t sys_clock_cycle_get_32(void) { return systimer_ll_get_counter_value_low(SYSTIMER_COUNTER_1); } + +uint64_t sys_clock_cycle_get_64(void) +{ + k_spinlock_key_t key = k_spin_lock(&lock); + uint64_t ret = systimer_ll_get_counter_value_low(SYSTIMER_COUNTER_1); + + ret |= (uint64_t)systimer_ll_get_counter_value_high(SYSTIMER_COUNTER_1) << 32; + + k_spin_unlock(&lock, key); + + return ret; +} diff --git a/drivers/timer/hpet.c b/drivers/timer/hpet.c index e01cc9d025f..29ea1bd0cb6 100644 --- a/drivers/timer/hpet.c +++ b/drivers/timer/hpet.c @@ -438,6 +438,12 @@ uint32_t sys_clock_cycle_get_32(void) return (uint32_t)hpet_counter_get(); } +__pinned_func +uint64_t sys_clock_cycle_get_64(void) +{ + return hpet_counter_get(); +} + __pinned_func void sys_clock_idle_exit(void) { diff --git a/drivers/timer/litex_timer.c b/drivers/timer/litex_timer.c index 2a3b869bbae..847d4211b11 100644 --- a/drivers/timer/litex_timer.c +++ b/drivers/timer/litex_timer.c @@ -52,6 +52,20 @@ uint32_t sys_clock_cycle_get_32(void) return timer_total; } +uint64_t sys_clock_cycle_get_64(void) +{ + static struct k_spinlock lock; + uint64_t timer_total; + k_spinlock_key_t key = k_spin_lock(&lock); + + litex_write8(UPDATE_TOTAL, TIMER_TOTAL_UPDATE); + timer_total = litex_read64(TIMER_TOTAL); + + k_spin_unlock(&lock, key); + + return timer_total; +} + /* tickless kernel is not supported */ uint32_t sys_clock_elapsed(void) { diff --git a/drivers/timer/mcux_os_timer.c b/drivers/timer/mcux_os_timer.c index 6ec70d611d9..0849e56bc81 100644 --- a/drivers/timer/mcux_os_timer.c +++ b/drivers/timer/mcux_os_timer.c @@ -127,3 +127,8 @@ uint32_t sys_clock_cycle_get_32(void) { return (uint32_t)OSTIMER_GetCurrentTimerValue(base); } + +uint64_t sys_clock_cycle_get_64(void) +{ + return OSTIMER_GetCurrentTimerValue(base); +} diff --git a/drivers/timer/native_posix_timer.c b/drivers/timer/native_posix_timer.c index 3b8e3219ceb..998eff6cf74 100644 --- a/drivers/timer/native_posix_timer.c +++ b/drivers/timer/native_posix_timer.c @@ -32,6 +32,11 @@ uint32_t sys_clock_cycle_get_32(void) return hwm_get_time(); } +uint64_t sys_clock_cycle_get_64(void) +{ + return hwm_get_time(); +} + /** * Interrupt handler for the timer interrupt * Announce to the kernel that a number of ticks have passed diff --git a/drivers/timer/npcx_itim_timer.c b/drivers/timer/npcx_itim_timer.c index 6e727327062..8c3bf6078d2 100644 --- a/drivers/timer/npcx_itim_timer.c +++ b/drivers/timer/npcx_itim_timer.c @@ -267,6 +267,17 @@ uint32_t sys_clock_cycle_get_32(void) return (uint32_t)(current); } +uint64_t sys_clock_cycle_get_64(void) +{ + k_spinlock_key_t key = k_spin_lock(&lock); + uint64_t current = npcx_itim_get_sys_cyc64(); + + k_spin_unlock(&lock, key); + + /* Return how many cycles since system kernel timer start counting */ + return current; +} + int sys_clock_driver_init(const struct device *dev) { ARG_UNUSED(dev); diff --git a/drivers/timer/riscv_machine_timer.c b/drivers/timer/riscv_machine_timer.c index 0211dcc1e57..7d9ace9d637 100644 --- a/drivers/timer/riscv_machine_timer.c +++ b/drivers/timer/riscv_machine_timer.c @@ -147,3 +147,8 @@ uint32_t sys_clock_cycle_get_32(void) { return (uint32_t)mtime(); } + +uint64_t sys_clock_cycle_get_64(void) +{ + return mtime(); +} diff --git a/include/arch/arc/v2/misc.h b/include/arch/arc/v2/misc.h index efc98b5d983..ea9e29dd52f 100644 --- a/include/arch/arc/v2/misc.h +++ b/include/arch/arc/v2/misc.h @@ -27,6 +27,13 @@ static inline uint32_t arch_k_cycle_get_32(void) { return sys_clock_cycle_get_32(); } + +extern uint64_t sys_clock_cycle_get_64(void); + +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} #endif #ifdef __cplusplus diff --git a/include/arch/arm/aarch32/misc.h b/include/arch/arm/aarch32/misc.h index 9c8e95523e2..6881ceb9ffd 100644 --- a/include/arch/arm/aarch32/misc.h +++ b/include/arch/arm/aarch32/misc.h @@ -26,6 +26,13 @@ static inline uint32_t arch_k_cycle_get_32(void) return sys_clock_cycle_get_32(); } +extern uint64_t sys_clock_cycle_get_64(void); + +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} + static ALWAYS_INLINE void arch_nop(void) { __asm__ volatile("nop"); diff --git a/include/arch/arm64/misc.h b/include/arch/arm64/misc.h index 3e9f93b638f..946869db6a0 100644 --- a/include/arch/arm64/misc.h +++ b/include/arch/arm64/misc.h @@ -27,6 +27,13 @@ static inline uint32_t arch_k_cycle_get_32(void) return sys_clock_cycle_get_32(); } +extern uint64_t sys_clock_cycle_get_64(void); + +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} + static ALWAYS_INLINE void arch_nop(void) { __asm__ volatile("nop"); diff --git a/include/arch/nios2/arch.h b/include/arch/nios2/arch.h index 78fcf791813..333dccdd53b 100644 --- a/include/arch/nios2/arch.h +++ b/include/arch/nios2/arch.h @@ -178,6 +178,13 @@ static inline uint32_t arch_k_cycle_get_32(void) return sys_clock_cycle_get_32(); } +extern uint64_t sys_clock_cycle_get_64(void); + +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} + static ALWAYS_INLINE void arch_nop(void) { __asm__ volatile("nop"); diff --git a/include/arch/posix/arch.h b/include/arch/posix/arch.h index 095f90f9d69..2e351ec6a20 100644 --- a/include/arch/posix/arch.h +++ b/include/arch/posix/arch.h @@ -51,6 +51,13 @@ static inline uint32_t arch_k_cycle_get_32(void) return sys_clock_cycle_get_32(); } +extern uint64_t sys_clock_cycle_get_64(void); + +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} + static ALWAYS_INLINE void arch_nop(void) { __asm__ volatile("nop"); diff --git a/include/arch/riscv/arch.h b/include/arch/riscv/arch.h index f317eef8d4d..d0379b614a0 100644 --- a/include/arch/riscv/arch.h +++ b/include/arch/riscv/arch.h @@ -354,6 +354,13 @@ static inline uint32_t arch_k_cycle_get_32(void) return sys_clock_cycle_get_32(); } +extern uint64_t sys_clock_cycle_get_64(void); + +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} + #ifdef CONFIG_USERSPACE #include #endif /* CONFIG_USERSPACE */ diff --git a/include/arch/sparc/arch.h b/include/arch/sparc/arch.h index bac00d86e9e..c9cf466e123 100644 --- a/include/arch/sparc/arch.h +++ b/include/arch/sparc/arch.h @@ -100,6 +100,12 @@ static inline uint32_t arch_k_cycle_get_32(void) return sys_clock_cycle_get_32(); } +extern uint64_t sys_clock_cycle_get_64(void); + +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} struct __esf { uint32_t out[8]; diff --git a/include/arch/x86/arch.h b/include/arch/x86/arch.h index 95d956dae1d..3982f8ae8b5 100644 --- a/include/arch/x86/arch.h +++ b/include/arch/x86/arch.h @@ -255,6 +255,14 @@ static inline uint32_t arch_k_cycle_get_32(void) return sys_clock_cycle_get_32(); } +extern uint64_t sys_clock_cycle_get_64(void); + +__pinned_func +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} + static ALWAYS_INLINE bool arch_irq_unlocked(unsigned int key) { return (key & 0x200) != 0; diff --git a/include/arch/xtensa/arch.h b/include/arch/xtensa/arch.h index 15cd981ceb2..8481b4ed011 100644 --- a/include/arch/xtensa/arch.h +++ b/include/arch/xtensa/arch.h @@ -63,6 +63,13 @@ static inline uint32_t arch_k_cycle_get_32(void) return sys_clock_cycle_get_32(); } +extern uint64_t sys_clock_cycle_get_64(void); + +static inline uint64_t arch_k_cycle_get_64(void) +{ + return sys_clock_cycle_get_64(); +} + static ALWAYS_INLINE void arch_nop(void) { __asm__ volatile("nop"); diff --git a/include/kernel.h b/include/kernel.h index 96d56a5fc11..340a87142c1 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -1639,6 +1639,27 @@ static inline uint32_t k_cycle_get_32(void) return arch_k_cycle_get_32(); } +/** + * @brief Read the 64-bit hardware clock. + * + * This routine returns the current time in 64-bits, as measured by the + * system's hardware clock, if available. + * + * @see CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER + * + * @return Current hardware clock up-counter (in cycles). + */ +static inline uint64_t k_cycle_get_64(void) +{ + if (!IS_ENABLED(CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER)) { + __ASSERT(0, "64-bit cycle counter not enabled on this platform. " + "See CONFIG_TIMER_HAS_64BIT_CYCLE_COUNTER"); + return 0; + } + + return arch_k_cycle_get_64(); +} + /** * @} */ diff --git a/include/sys/arch_interface.h b/include/sys/arch_interface.h index 6b280d8d1e5..ea423505119 100644 --- a/include/sys/arch_interface.h +++ b/include/sys/arch_interface.h @@ -58,6 +58,13 @@ typedef void (*k_thread_entry_t)(void *p1, void *p2, void *p3); */ static inline uint32_t arch_k_cycle_get_32(void); +/** + * Obtain the current cycle count, in units that are hardware-specific + * + * @see k_cycle_get_64() + */ +static inline uint64_t arch_k_cycle_get_64(void); + /** @} */ diff --git a/subsys/testsuite/ztest/include/arch/cpu.h b/subsys/testsuite/ztest/include/arch/cpu.h index 61bba9751b4..1e39a9b9709 100644 --- a/subsys/testsuite/ztest/include/arch/cpu.h +++ b/subsys/testsuite/ztest/include/arch/cpu.h @@ -27,6 +27,11 @@ static inline uint32_t arch_k_cycle_get_32(void) return 0; } +static inline uint64_t arch_k_cycle_get_64(void) +{ + return 0; +} + static ALWAYS_INLINE unsigned int arch_irq_lock(void) { return 0;