From 31be41653a659a52460734cb8fe1da27e6d5629e Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Mon, 20 Apr 2015 11:08:22 +0200 Subject: timecounter: Port to RTEMS New test sptests/timecounter01. Update #2271. --- cpukit/sapi/Makefile.am | 3 + cpukit/sapi/include/rtems/bsd.h | 141 ++++++++++ cpukit/sapi/include/rtems/timecounter.h | 304 +++++++++++++++++++++ cpukit/sapi/preinstall.am | 8 + cpukit/sapi/src/tcsimpleinstall.c | 52 ++++ cpukit/score/Makefile.am | 12 + cpukit/score/include/rtems/score/timecounter.h | 199 ++++++++++++++ cpukit/score/include/rtems/score/timecounterimpl.h | 49 ++++ cpukit/score/include/sys/timeffc.h | 2 + cpukit/score/include/sys/timetc.h | 2 + cpukit/score/preinstall.am | 33 +++ cpukit/score/src/kern_tc.c | 171 ++++++++++++ 12 files changed, 976 insertions(+) create mode 100644 cpukit/sapi/include/rtems/bsd.h create mode 100644 cpukit/sapi/include/rtems/timecounter.h create mode 100644 cpukit/sapi/src/tcsimpleinstall.c create mode 100644 cpukit/score/include/rtems/score/timecounter.h create mode 100644 cpukit/score/include/rtems/score/timecounterimpl.h (limited to 'cpukit') diff --git a/cpukit/sapi/Makefile.am b/cpukit/sapi/Makefile.am index 070800e636..d7fd9aac63 100644 --- a/cpukit/sapi/Makefile.am +++ b/cpukit/sapi/Makefile.am @@ -4,6 +4,7 @@ include $(top_srcdir)/automake/compile.am include_rtemsdir = $(includedir)/rtems include_rtems_HEADERS = include/confdefs.h +include_rtems_HEADERS += include/rtems/bsd.h include_rtems_HEADERS += include/rtems/chain.h include_rtems_HEADERS += include/rtems/config.h include_rtems_HEADERS += include/rtems/counter.h @@ -19,6 +20,7 @@ include_rtems_HEADERS += include/rtems/rbheap.h include_rtems_HEADERS += include/rtems/rbtree.h include_rtems_HEADERS += include/rtems/scheduler.h include_rtems_HEADERS += include/rtems/sptables.h +include_rtems_HEADERS += include/rtems/timecounter.h include_rtems_HEADERS += include/rtems/timespec.h EXTRA_DIST = include/rtems/README @@ -39,6 +41,7 @@ libsapi_a_SOURCES += src/delayticks.c libsapi_a_SOURCES += src/delaynano.c libsapi_a_SOURCES += src/profilingiterate.c libsapi_a_SOURCES += src/profilingreportxml.c +libsapi_a_SOURCES += src/tcsimpleinstall.c libsapi_a_CPPFLAGS = $(AM_CPPFLAGS) include $(srcdir)/preinstall.am diff --git a/cpukit/sapi/include/rtems/bsd.h b/cpukit/sapi/include/rtems/bsd.h new file mode 100644 index 0000000000..0c44e3787d --- /dev/null +++ b/cpukit/sapi/include/rtems/bsd.h @@ -0,0 +1,141 @@ +/** + * @file + * + * @ingroup BSD + * + * @brief BSD Compatibility API + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_BSD_H +#define _RTEMS_BSD_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup BSD BSD Compatibility Support + * + * @{ + */ + +/** + * @copydoc _Timecounter_Bintime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_bintime( struct bintime *bt ) +{ + _Timecounter_Bintime( bt ); +} + +/** + * @copydoc _Timecounter_Nanotime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_nanotime( struct timespec *ts ) +{ + _Timecounter_Nanotime( ts ); +} + +/** + * @copydoc _Timecounter_Microtime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_microtime( struct timeval *tv ) +{ + _Timecounter_Microtime( tv ); +} + +/** + * @copydoc _Timecounter_Binuptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_binuptime( struct bintime *bt ) +{ + _Timecounter_Binuptime( bt ); +} + +/** + * @copydoc _Timecounter_Nanouptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_nanouptime( struct timespec *ts ) +{ + _Timecounter_Nanouptime( ts ); +} + +/** + * @copydoc _Timecounter_Microtime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_microuptime( struct timeval *tv ) +{ + _Timecounter_Microuptime( tv ); +} + +/** + * @copydoc _Timecounter_Getbintime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getbintime( struct bintime *bt ) +{ + _Timecounter_Getbintime( bt ); +} + +/** + * @copydoc _Timecounter_Getnanotime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getnanotime( struct timespec *ts ) +{ + _Timecounter_Getnanotime( ts ); +} + +/** + * @copydoc _Timecounter_Getmicrotime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getmicrotime( struct timeval *tv ) +{ + _Timecounter_Getmicrotime( tv ); +} + +/** + * @copydoc _Timecounter_Getbinuptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getbinuptime( struct bintime *bt ) +{ + _Timecounter_Getbinuptime( bt ); +} + +/** + * @copydoc _Timecounter_Getnanouptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getnanouptime( struct timespec *ts ) +{ + _Timecounter_Getnanouptime( ts ); +} + +/** + * @copydoc _Timecounter_Getmicrouptime() + */ +RTEMS_INLINE_ROUTINE void rtems_bsd_getmicrouptime( struct timeval *tv ) +{ + _Timecounter_Getmicrouptime( tv ); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_BSD_H */ diff --git a/cpukit/sapi/include/rtems/timecounter.h b/cpukit/sapi/include/rtems/timecounter.h new file mode 100644 index 0000000000..04bc534d55 --- /dev/null +++ b/cpukit/sapi/include/rtems/timecounter.h @@ -0,0 +1,304 @@ +/** + * @file + * + * @ingroup SAPITimecounter + * + * @brief Timecounter API + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_TIMECOUNTER_H +#define _RTEMS_TIMECOUNTER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup SAPITimecounter Timecounter Support + * + * @{ + */ + +/** + * @brief Timecounter quality for the clock drivers. + * + * Timecounter with higher quality value are used in favour of those with lower + * quality value. + */ +#define RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER 100 + +/** + * @copydoc _Timecounter_Install() + * + * Below is an exemplary code snippet that shows the adjustable parameters and + * the following call of the install routine. + * + * @code + * struct timecounter tc; + * + * uint32_t get_timecount( struct timecounter *tc ) + * { + * return some_free_running_counter; + * } + * + * void install( void ) + * { + * tc.tc_get_timecount = get_timecount; + * tc.tc_counter_mask = 0xffffffff; + * tc.tc_frequency = 123456; + * tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + * rtems_timecounter_install( &tc ); + * } + * @endcode + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_install( + struct timecounter *tc +) +{ + _Timecounter_Install( tc ); +} + +/** + * @copydoc _Timecounter_Tick() + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_tick(void) +{ + _Timecounter_Tick(); +} + +/** + * @brief Simple timecounter to support legacy clock drivers. + */ +typedef struct { + struct timecounter tc; + uint64_t scaler; + uint32_t real_interval; + uint32_t binary_interval; +} rtems_timecounter_simple; + +/** + * @brief Returns the current value of a simple timecounter. + */ +typedef uint32_t rtems_timecounter_simple_get( + rtems_timecounter_simple *tc +); + +/** + * @brief Returns true if the interrupt of a simple timecounter is pending, and + * false otherwise. + */ +typedef bool rtems_timecounter_simple_is_pending( + rtems_timecounter_simple *tc +); + +/** + * @brief Initializes and installs a simple timecounter. + * + * A simple timecounter can be used if the hardware provides no free running + * counter or only the module used for the clock tick is available. The period + * of the simple timecounter equals the clock tick interval. The interval is + * scaled up to the next power of two. + * + * @param[in] tc Zero initialized simple timecounter. + * @param[in] frequency_in_hz The timecounter frequency in Hz. + * @param[in] timecounter_ticks_per_clock_tick The timecounter ticks per clock tick. + * @param[in] get_timecount The method to get the current time count. + * + * @code + * #include + * + * static rtems_timecounter_simple some_tc; + * + * static uint32_t some_tc_get( rtems_timecounter_simple *tc ) + * { + * return some.value; + * } + * + * static bool some_tc_is_pending( rtems_timecounter_simple *tc ) + * { + * return some.is_pending; + * } + * + * static uint32_t some_tc_get_timecount( struct timecounter *tc ) + * { + * return rtems_timecounter_simple_downcounter_get( + * tc, + * some_tc_get, + * some_tc_is_pending + * ); + * } + * + * static void some_tc_tick( void ) + * { + * rtems_timecounter_simple_downcounter_tick( &some_tc, some_tc_get ); + * } + * + * void install( void ) + * { + * uint32_t frequency = 123456; + * uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick(); + * uint32_t timecounter_ticks_per_clock_tick = + * ( frequency * us_per_tick ) / 1000000; + * + * rtems_timecounter_simple_install( + * &some_tc, + * frequency, + * timecounter_ticks_per_clock_tick, + * some_tc_get_timecount + * ); + * } + * @endcode + * + * @see rtems_timecounter_simple_downcounter_get(), + * rtems_timecounter_simple_downcounter_tick(), + * rtems_timecounter_simple_upcounter_get() and + * rtems_timecounter_simple_upcounter_tick(). + */ +void rtems_timecounter_simple_install( + rtems_timecounter_simple *tc, + uint32_t frequency_in_hz, + uint32_t timecounter_ticks_per_clock_tick, + timecounter_get_t *get_timecount +); + +/** + * @brief Maps a simple timecounter value into its binary frequency domain. + * + * @param[in] tc The simple timecounter. + * @param[in] value The value of the simple timecounter. + * + * @return The scaled value. + */ +RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_scale( + const rtems_timecounter_simple *tc, + uint32_t value +) +{ + return (uint32_t) ( ( value * tc->scaler ) >> 32 ); +} + +/** + * @brief Performs a simple timecounter tick for downcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_simple_downcounter_tick( + rtems_timecounter_simple *tc, + rtems_timecounter_simple_get get +) +{ + uint32_t current; + + current = rtems_timecounter_simple_scale( + tc, + tc->real_interval - ( *get )( tc ) + ); + + _Timecounter_Tick_simple( tc->binary_interval, current ); +} + +/** + * @brief Performs a simple timecounter tick for upcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + */ +RTEMS_INLINE_ROUTINE void rtems_timecounter_simple_upcounter_tick( + rtems_timecounter_simple *tc, + rtems_timecounter_simple_get get +) +{ + uint32_t current; + + current = rtems_timecounter_simple_scale( tc, ( *get )( tc ) ); + + _Timecounter_Tick_simple( tc->binary_interval, current ); +} + +/** + * @brief Gets the simple timecounter value mapped to its binary frequency + * domain for downcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + * @param[in] is_pending The method which indicates if the interrupt of the + * simple timecounter is pending. + */ +RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_downcounter_get( + struct timecounter *tc_base, + rtems_timecounter_simple_get get, + rtems_timecounter_simple_is_pending is_pending +) +{ + rtems_timecounter_simple *tc; + uint32_t counter; + uint32_t interval; + + tc = (rtems_timecounter_simple *) tc_base; + counter = ( *get )( tc ); + interval = tc->real_interval; + + if ( ( *is_pending )( tc ) ) { + counter = ( *get )( tc ); + interval *= 2; + } + + return rtems_timecounter_simple_scale( tc, interval - counter ); +} + +/** + * @brief Gets the simple timecounter value mapped to its binary frequency + * domain for upcounters. + * + * @param[in] tc The simple timecounter. + * @param[in] get The method to get the value of the simple timecounter. + * @param[in] is_pending The method which indicates if the interrupt of the + * simple timecounter is pending. + */ +RTEMS_INLINE_ROUTINE uint32_t rtems_timecounter_simple_upcounter_get( + struct timecounter *tc_base, + rtems_timecounter_simple_get get, + rtems_timecounter_simple_is_pending is_pending +) +{ + rtems_timecounter_simple *tc; + uint32_t counter; + uint32_t interval; + + tc = (rtems_timecounter_simple *) tc_base; + counter = ( *get )( tc ); + interval = 0; + + if ( ( *is_pending )( tc ) ) { + counter = ( *get )( tc ); + interval = tc->real_interval; + } + + return rtems_timecounter_simple_scale( tc, interval + counter ); +} + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_TIMECOUNTER_H */ diff --git a/cpukit/sapi/preinstall.am b/cpukit/sapi/preinstall.am index 3f864bb61d..8a4e54ffd2 100644 --- a/cpukit/sapi/preinstall.am +++ b/cpukit/sapi/preinstall.am @@ -22,6 +22,10 @@ $(PROJECT_INCLUDE)/rtems/confdefs.h: include/confdefs.h $(PROJECT_INCLUDE)/rtems $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/confdefs.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/confdefs.h +$(PROJECT_INCLUDE)/rtems/bsd.h: include/rtems/bsd.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/bsd.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/bsd.h + $(PROJECT_INCLUDE)/rtems/chain.h: include/rtems/chain.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/chain.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/chain.h @@ -82,6 +86,10 @@ $(PROJECT_INCLUDE)/rtems/sptables.h: include/rtems/sptables.h $(PROJECT_INCLUDE) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/sptables.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/sptables.h +$(PROJECT_INCLUDE)/rtems/timecounter.h: include/rtems/timecounter.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/timecounter.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/timecounter.h + $(PROJECT_INCLUDE)/rtems/timespec.h: include/rtems/timespec.h $(PROJECT_INCLUDE)/rtems/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/timespec.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/timespec.h diff --git a/cpukit/sapi/src/tcsimpleinstall.c b/cpukit/sapi/src/tcsimpleinstall.c new file mode 100644 index 0000000000..563edd7c87 --- /dev/null +++ b/cpukit/sapi/src/tcsimpleinstall.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#if HAVE_CONFIG_H + #include "config.h" +#endif + +#include + +void rtems_timecounter_simple_install( + rtems_timecounter_simple *tc, + uint32_t frequency_in_hz, + uint32_t counter_ticks_per_clock_tick, + timecounter_get_t *get_timecount +) +{ + uint32_t power_of_two = 1; + uint32_t mask; + uint64_t scaler; + int i; + + for ( i = 0; i < 32; ++i ) { + if ( power_of_two >= counter_ticks_per_clock_tick ) { + break; + } + + power_of_two *= 2; + } + + mask = ( 2 * power_of_two ) - 1; + scaler = ( (uint64_t) power_of_two << 32 ) / counter_ticks_per_clock_tick; + + tc->scaler = scaler; + tc->real_interval = counter_ticks_per_clock_tick; + tc->binary_interval = ( mask + 1 ) / 2; + tc->tc.tc_get_timecount = get_timecount; + tc->tc.tc_counter_mask = mask; + tc->tc.tc_frequency = (uint32_t) ( ( frequency_in_hz * scaler ) >> 32 ); + tc->tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER; + _Timecounter_Install( &tc->tc ); +} diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index b6b7c9fa74..a16aedac1d 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -5,6 +5,15 @@ SUBDIRS = cpu ## include +include_sysdir = $(includedir)/sys + +include_sys_HEADERS = +include_sys_HEADERS += include/sys/_ffcounter.h +include_sys_HEADERS += include/sys/timeffc.h +include_sys_HEADERS += include/sys/timepps.h +include_sys_HEADERS += include/sys/timetc.h +include_sys_HEADERS += include/sys/timex.h + include_rtemsdir = $(includedir)/rtems include_rtems_HEADERS = include/rtems/debug.h @@ -85,6 +94,8 @@ include_rtems_score_HEADERS += include/rtems/score/threadqimpl.h include_rtems_score_HEADERS += include/rtems/score/timespec.h include_rtems_score_HEADERS += include/rtems/score/timestamp.h include_rtems_score_HEADERS += include/rtems/score/timestamp64.h +include_rtems_score_HEADERS += include/rtems/score/timecounter.h +include_rtems_score_HEADERS += include/rtems/score/timecounterimpl.h include_rtems_score_HEADERS += include/rtems/score/tls.h include_rtems_score_HEADERS += include/rtems/score/tod.h include_rtems_score_HEADERS += include/rtems/score/todimpl.h @@ -344,6 +355,7 @@ libscore_a_SOURCES += src/profilingisrentryexit.c libscore_a_SOURCES += src/once.c libscore_a_SOURCES += src/resourceiterate.c libscore_a_SOURCES += src/smpbarrierwait.c +libscore_a_SOURCES += src/kern_tc.c EXTRA_DIST = src/Unlimited.txt diff --git a/cpukit/score/include/rtems/score/timecounter.h b/cpukit/score/include/rtems/score/timecounter.h new file mode 100644 index 0000000000..0d17cc7ce3 --- /dev/null +++ b/cpukit/score/include/rtems/score/timecounter.h @@ -0,0 +1,199 @@ +/** + * @file + * + * @ingroup ScoreTimecounter + * + * @brief Timecounter API + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_SCORE_TIMECOUNTER_H +#define _RTEMS_SCORE_TIMECOUNTER_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @defgroup ScoreTimecounter Timecounter Handler + * + * @ingroup Score + * + * @{ + */ + +/** + * @brief Returns the wall clock time in the bintime format. + * + * @param[out] bt Returns the wall clock time. + */ +void _Timecounter_Bintime( struct bintime *bt ); + +/** + * @brief Returns the wall clock time in the timespec format. + * + * @param[out] ts Returns the wall clock time. + */ +void _Timecounter_Nanotime( struct timespec *ts ); + +/** + * @brief Returns the wall clock time in the timeval format. + * + * @param[out] tv Returns the wall clock time. + */ +void _Timecounter_Microtime( struct timeval *tv ); + +/** + * @brief Returns the uptime in the bintime format. + * + * @param[out] bt Returns the uptime. + */ +void _Timecounter_Binuptime( struct bintime *bt ); + +/** + * @brief Returns the uptime in the timespec format. + * + * @param[out] ts Returns the uptime. + */ +void _Timecounter_Nanouptime( struct timespec *ts ); + +/** + * @brief Returns the uptime in the timeval format. + * + * @param[out] tv Returns the uptime. + */ +void _Timecounter_Microuptime( struct timeval *tv ); + +/** + * @brief Returns the wall clock time in the bintime format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Bintime() variant. + * + * @param[out] ts Returns the wall clock time. + */ +void _Timecounter_Getbintime( struct bintime *bt ); + +/** + * @brief Returns the wall clock time in the timespec format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Nanotime() variant. + * + * @param[out] ts Returns the wall clock time. + * + * @see _Timecounter_Getbintime(). + */ +void _Timecounter_Getnanotime( struct timespec *ts ); + +/** + * @brief Returns the wall clock time in the timeval format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Microtime() variant. + * + * @param[out] tv Returns the wall clock time. + * + * @see _Timecounter_Getbintime(). + */ +void _Timecounter_Getmicrotime( struct timeval *tv ); + +/** + * @brief Returns the uptime in the bintime format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Binuptime() variant. + * + * @param[out] ts Returns the uptime. + */ +void _Timecounter_Getbinuptime( struct bintime *bt ); + +/** + * @brief Returns the uptime in the timespec format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Nanouptime() variant. + * + * @param[out] ts Returns the uptime. + */ +void _Timecounter_Getnanouptime( struct timespec *ts ); + +/** + * @brief Returns the uptime in the timeval format. + * + * This function obtains the time with a lower overhead and lower accuracy + * compared to the _Timecounter_Microuptime() variant. + * + * @param[out] tv Returns the uptime. + */ +void _Timecounter_Getmicrouptime( struct timeval *tv ); + +/** + * @brief Installs the timecounter. + * + * The timecounter structure must contain valid values in the fields + * tc_get_timecount, tc_counter_mask, tc_frequency and tc_quality. All other + * fields must be zero initialized. + * + * @param[in] tc The timecounter. + */ +void _Timecounter_Install( struct timecounter *tc ); + +/** + * @brief Performs a timecounter tick. + */ +void _Timecounter_Tick( void ); + +/** + * @brief Performs a simple timecounter tick. + * + * This is a special purpose tick function for simple timecounter to support + * legacy clock drivers. + * + * @param[in] delta The time in timecounter ticks elapsed since the last call + * to _Timecounter_Tick_simple(). + * @param[in] offset The current value of the timecounter. + */ +void _Timecounter_Tick_simple( uint32_t delta, uint32_t offset ); + +/** + * @brief The wall clock time in seconds. + */ +extern volatile time_t _Timecounter_Time_second; + +/** + * @brief The uptime in seconds. + * + * For compatibility with the FreeBSD network stack the initial value is one + * second. + */ +extern volatile time_t _Timecounter_Time_uptime; + +/** + * @brief The current timecounter. + */ +extern struct timecounter *_Timecounter; + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_SCORE_TIMECOUNTER_H */ diff --git a/cpukit/score/include/rtems/score/timecounterimpl.h b/cpukit/score/include/rtems/score/timecounterimpl.h new file mode 100644 index 0000000000..dd47aacc04 --- /dev/null +++ b/cpukit/score/include/rtems/score/timecounterimpl.h @@ -0,0 +1,49 @@ +/** + * @file + * + * @ingroup ScoreTimecounter + * + * @brief Timecounter Implementation + */ + +/* + * Copyright (c) 2015 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Dornierstr. 4 + * 82178 Puchheim + * Germany + * + * + * The license and distribution terms for this file may be + * found in the file LICENSE in this distribution or at + * http://www.rtems.org/license/LICENSE. + */ + +#ifndef _RTEMS_SCORE_TIMECOUNTERIMPL_H +#define _RTEMS_SCORE_TIMECOUNTERIMPL_H + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/** + * @addtogroup ScoreTimecounter + * + * @{ + */ + +void _Timecounter_Initialize( void ); + +void _Timecounter_Set_clock( const struct timespec *ts ); + +/** @} */ + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* _RTEMS_SCORE_TIMECOUNTERIMPL_H */ diff --git a/cpukit/score/include/sys/timeffc.h b/cpukit/score/include/sys/timeffc.h index 893afe8bda..b3a1cd9ce7 100644 --- a/cpukit/score/include/sys/timeffc.h +++ b/cpukit/score/include/sys/timeffc.h @@ -55,11 +55,13 @@ struct ffclock_estimate { #if __BSD_VISIBLE #ifdef _KERNEL +#ifndef __rtems__ /* Define the kern.sysclock sysctl tree. */ SYSCTL_DECL(_kern_sysclock); /* Define the kern.sysclock.ffclock sysctl tree. */ SYSCTL_DECL(_kern_sysclock_ffclock); +#endif /* __rtems__ */ /* * Index into the sysclocks array for obtaining the ASCII name of a particular diff --git a/cpukit/score/include/sys/timetc.h b/cpukit/score/include/sys/timetc.h index 9d269a780b..88e90dedac 100644 --- a/cpukit/score/include/sys/timetc.h +++ b/cpukit/score/include/sys/timetc.h @@ -12,9 +12,11 @@ #ifndef _SYS_TIMETC_H_ #define _SYS_TIMETC_H_ +#ifndef __rtems__ #ifndef _KERNEL #error "no user-serviceable parts inside" #endif +#endif /* __rtems__ */ /*- * `struct timecounter' is the interface between the hardware which implements diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 62e15720f4..13ea020c9e 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -13,6 +13,31 @@ all-am: $(PREINSTALL_FILES) PREINSTALL_FILES = CLEANFILES = $(PREINSTALL_FILES) +$(PROJECT_INCLUDE)/sys/$(dirstamp): + @$(MKDIR_P) $(PROJECT_INCLUDE)/sys + @: > $(PROJECT_INCLUDE)/sys/$(dirstamp) +PREINSTALL_DIRS += $(PROJECT_INCLUDE)/sys/$(dirstamp) + +$(PROJECT_INCLUDE)/sys/_ffcounter.h: include/sys/_ffcounter.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/_ffcounter.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/_ffcounter.h + +$(PROJECT_INCLUDE)/sys/timeffc.h: include/sys/timeffc.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/timeffc.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/timeffc.h + +$(PROJECT_INCLUDE)/sys/timepps.h: include/sys/timepps.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/timepps.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/timepps.h + +$(PROJECT_INCLUDE)/sys/timetc.h: include/sys/timetc.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/timetc.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/timetc.h + +$(PROJECT_INCLUDE)/sys/timex.h: include/sys/timex.h $(PROJECT_INCLUDE)/sys/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/sys/timex.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/sys/timex.h + $(PROJECT_INCLUDE)/rtems/$(dirstamp): @$(MKDIR_P) $(PROJECT_INCLUDE)/rtems @: > $(PROJECT_INCLUDE)/rtems/$(dirstamp) @@ -323,6 +348,14 @@ $(PROJECT_INCLUDE)/rtems/score/timestamp64.h: include/rtems/score/timestamp64.h $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timestamp64.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timestamp64.h +$(PROJECT_INCLUDE)/rtems/score/timecounter.h: include/rtems/score/timecounter.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timecounter.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timecounter.h + +$(PROJECT_INCLUDE)/rtems/score/timecounterimpl.h: include/rtems/score/timecounterimpl.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) + $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timecounterimpl.h +PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timecounterimpl.h + $(PROJECT_INCLUDE)/rtems/score/tls.h: include/rtems/score/tls.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp) $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/tls.h PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/tls.h diff --git a/cpukit/score/src/kern_tc.c b/cpukit/score/src/kern_tc.c index 246c98bb90..bca73ecb19 100644 --- a/cpukit/score/src/kern_tc.c +++ b/cpukit/score/src/kern_tc.c @@ -13,6 +13,27 @@ * of Melbourne under sponsorship from the FreeBSD Foundation. */ +#ifdef __rtems__ +#define _KERNEL +#define bintime _Timecounter_Bintime +#define binuptime _Timecounter_Binuptime +#define boottimebin _Timecounter_Boottimebin +#define getbintime _Timecounter_Getbintime +#define getbinuptime _Timecounter_Getbinuptime +#define getmicrotime _Timecounter_Getmicrotime +#define getmicrouptime _Timecounter_Getmicrouptime +#define getnanotime _Timecounter_Getnanotime +#define getnanouptime _Timecounter_Getnanouptime +#define microtime _Timecounter_Microtime +#define microuptime _Timecounter_Microuptime +#define nanotime _Timecounter_Nanotime +#define nanouptime _Timecounter_Nanouptime +#define tc_init _Timecounter_Install +#define timecounter _Timecounter +#define time_second _Timecounter_Time_second +#define time_uptime _Timecounter_Time_uptime +#include +#endif /* __rtems__ */ #include __FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); @@ -21,20 +42,42 @@ __FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); #include "opt_ffclock.h" #include +#ifndef __rtems__ #include #include +#else /* __rtems__ */ +#include +#endif /* __rtems__ */ #ifdef FFCLOCK #include #include #endif +#ifndef __rtems__ #include #include #include +#endif /* __rtems__ */ #include #include #include #include +#ifndef __rtems__ #include +#endif /* __rtems__ */ +#ifdef __rtems__ +#include +ISR_LOCK_DEFINE(static, _Timecounter_Lock, "Timecounter"); +#define hz rtems_clock_get_ticks_per_second() +#define printf(...) +#define log(...) +static inline int +fls(int x) +{ + return x ? sizeof(x) * 8 - __builtin_clz(x) : 0; +} +/* FIXME: https://devel.rtems.org/ticket/2348 */ +#define ntp_update_second(a, b) do { (void) a; (void) b; } while (0) +#endif /* __rtems__ */ /* * A large step happens on boot. This constant detects such steps. @@ -53,9 +96,13 @@ __FBSDID("$FreeBSD r277406 2015-01-20T03:54:30Z$"); static uint32_t dummy_get_timecount(struct timecounter *tc) { +#ifndef __rtems__ static uint32_t now; return (++now); +#else /* __rtems__ */ + return 0; +#endif /* __rtems__ */ } static struct timecounter dummy_timecounter = { @@ -76,6 +123,7 @@ struct timehands { struct timehands *th_next; }; +#if defined(RTEMS_SMP) static struct timehands th0; static struct timehands th9 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th0}; static struct timehands th8 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th9}; @@ -86,6 +134,7 @@ static struct timehands th4 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th5}; static struct timehands th3 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th4}; static struct timehands th2 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th3}; static struct timehands th1 = { NULL, 0, 0, 0, {0, 0}, {0, 0}, {0, 0}, 0, &th2}; +#endif static struct timehands th0 = { &dummy_timecounter, 0, @@ -95,19 +144,26 @@ static struct timehands th0 = { {0, 0}, {0, 0}, 1, +#if defined(RTEMS_SMP) &th1 +#else + &th0 +#endif }; static struct timehands *volatile timehands = &th0; struct timecounter *timecounter = &dummy_timecounter; static struct timecounter *timecounters = &dummy_timecounter; +#ifndef __rtems__ int tc_min_ticktock_freq = 1; +#endif /* __rtems__ */ volatile time_t time_second = 1; volatile time_t time_uptime = 1; struct bintime boottimebin; +#ifndef __rtems__ struct timeval boottime; static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS); SYSCTL_PROC(_kern, KERN_BOOTTIME, boottime, CTLTYPE_STRUCT|CTLFLAG_RD, @@ -133,12 +189,16 @@ SYSCTL_PROC(_kern_timecounter, OID_AUTO, alloweddeviation, CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, 0, 0, sysctl_kern_timecounter_adjprecision, "I", "Allowed time interval deviation in percents"); +#endif /* __rtems__ */ static void tc_windup(void); +#ifndef __rtems__ static void cpu_tick_calibrate(int); +#endif /* __rtems__ */ void dtrace_getnanotime(struct timespec *tsp); +#ifndef __rtems__ static int sysctl_kern_boottime(SYSCTL_HANDLER_ARGS) { @@ -175,6 +235,7 @@ sysctl_kern_timecounter_freq(SYSCTL_HANDLER_ARGS) freq = tc->tc_frequency; return sysctl_handle_64(oidp, &freq, 0, req); } +#endif /* __rtems__ */ /* * Return the difference between the timehands' counter value now and what @@ -976,6 +1037,7 @@ getmicrotime(struct timeval *tvp) #endif /* FFCLOCK */ +#ifndef __rtems__ /* * This is a clone of getnanotime and used for walltimestamps. * The dtrace_ prefix prevents fbt from creating probes for @@ -993,6 +1055,7 @@ dtrace_getnanotime(struct timespec *tsp) *tsp = th->th_nanotime; } while (gen == 0 || gen != th->th_generation); } +#endif /* __rtems__ */ #ifdef FFCLOCK /* @@ -1006,6 +1069,7 @@ int sysclock_active = SYSCLOCK_FBCK; extern int time_status; extern long time_esterror; +#ifndef __rtems__ /* * Take a snapshot of sysclock data which can be used to compare system clocks * and generate timestamps after the fact. @@ -1137,6 +1201,7 @@ sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, return (0); } +#endif /* __rtems__ */ /* * Initialize a new timecounter and possibly use it. @@ -1144,6 +1209,7 @@ sysclock_snap2bintime(struct sysclock_snap *cs, struct bintime *bt, void tc_init(struct timecounter *tc) { +#ifndef __rtems__ uint32_t u; struct sysctl_oid *tc_root; @@ -1163,9 +1229,11 @@ tc_init(struct timecounter *tc) tc->tc_name, (uintmax_t)tc->tc_frequency, tc->tc_quality); } +#endif /* __rtems__ */ tc->tc_next = timecounters; timecounters = tc; +#ifndef __rtems__ /* * Set up sysctl tree for this counter. */ @@ -1196,11 +1264,16 @@ tc_init(struct timecounter *tc) if (tc->tc_quality == timecounter->tc_quality && tc->tc_frequency < timecounter->tc_frequency) return; +#endif /* __rtems__ */ (void)tc->tc_get_timecount(tc); (void)tc->tc_get_timecount(tc); timecounter = tc; +#ifdef __rtems__ + tc_windup(); +#endif /* __rtems__ */ } +#ifndef __rtems__ /* Report the frequency of the current timecounter. */ uint64_t tc_getfrequency(void) @@ -1208,29 +1281,42 @@ tc_getfrequency(void) return (timehands->th_counter->tc_frequency); } +#endif /* __rtems__ */ /* * Step our concept of UTC. This is done by modifying our estimate of * when we booted. * XXX: not locked. */ +#ifndef __rtems__ void tc_setclock(struct timespec *ts) +#else /* __rtems__ */ +void +_Timecounter_Set_clock(const struct timespec *ts) +#endif /* __rtems__ */ { +#ifndef __rtems__ struct timespec tbef, taft; +#endif /* __rtems__ */ struct bintime bt, bt2; +#ifndef __rtems__ cpu_tick_calibrate(1); nanotime(&tbef); +#endif /* __rtems__ */ timespec2bintime(ts, &bt); binuptime(&bt2); bintime_sub(&bt, &bt2); bintime_add(&bt2, &boottimebin); boottimebin = bt; +#ifndef __rtems__ bintime2timeval(&bt, &boottime); +#endif /* __rtems__ */ /* XXX fiddle all the little crinkly bits around the fiords... */ tc_windup(); +#ifndef __rtems__ nanotime(&taft); if (timestepwarnings) { log(LOG_INFO, @@ -1240,6 +1326,7 @@ tc_setclock(struct timespec *ts) (intmax_t)ts->tv_sec, ts->tv_nsec); } cpu_tick_calibrate(1); +#endif /* __rtems__ */ } /* @@ -1256,6 +1343,11 @@ tc_windup(void) uint32_t delta, ncount, ogen; int i; time_t t; +#ifdef __rtems__ + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire(&_Timecounter_Lock, &lock_context); +#endif /* __rtems__ */ /* * Make the next timehands a copy of the current one, but do not @@ -1333,16 +1425,20 @@ tc_windup(void) /* Now is a good time to change timecounters. */ if (th->th_counter != timecounter) { +#ifndef __rtems__ #ifndef __arm__ if ((timecounter->tc_flags & TC_FLAGS_C2STOP) != 0) cpu_disable_c2_sleep++; if ((th->th_counter->tc_flags & TC_FLAGS_C2STOP) != 0) cpu_disable_c2_sleep--; #endif +#endif /* __rtems__ */ th->th_counter = timecounter; th->th_offset_count = ncount; +#ifndef __rtems__ tc_min_ticktock_freq = max(1, timecounter->tc_frequency / (((uint64_t)timecounter->tc_counter_mask + 1) / 3)); +#endif /* __rtems__ */ #ifdef FFCLOCK ffclock_change_tc(th); #endif @@ -1401,9 +1497,15 @@ tc_windup(void) #endif timehands = th; +#ifndef __rtems__ timekeep_push_vdso(); +#endif /* __rtems__ */ +#ifdef __rtems__ + _ISR_lock_Release_and_ISR_enable(&_Timecounter_Lock, &lock_context); +#endif /* __rtems__ */ } +#ifndef __rtems__ /* Report or change the active timecounter hardware. */ static int sysctl_kern_timecounter_hardware(SYSCTL_HANDLER_ARGS) @@ -1468,7 +1570,9 @@ sysctl_kern_timecounter_choice(SYSCTL_HANDLER_ARGS) SYSCTL_PROC(_kern_timecounter, OID_AUTO, choice, CTLTYPE_STRING | CTLFLAG_RD, 0, 0, sysctl_kern_timecounter_choice, "A", "Timecounter hardware detected"); +#endif /* __rtems__ */ +#ifndef __rtems__ /* * RFC 2783 PPS-API implementation. */ @@ -1749,6 +1853,9 @@ pps_event(struct pps_state *pps, int event) /* Wakeup anyone sleeping in pps_fetch(). */ wakeup(pps); } +#else /* __rtems__ */ +/* FIXME: https://devel.rtems.org/ticket/2349 */ +#endif /* __rtems__ */ /* * Timecounters need to be updated every so often to prevent the hardware @@ -1757,10 +1864,13 @@ pps_event(struct pps_state *pps, int event) * the update frequency. */ +#ifndef __rtems__ static int tc_tick; SYSCTL_INT(_kern_timecounter, OID_AUTO, tick, CTLFLAG_RD, &tc_tick, 0, "Approximate number of hardclock ticks in a millisecond"); +#endif /* __rtems__ */ +#ifndef __rtems__ void tc_ticktock(int cnt) { @@ -1770,9 +1880,54 @@ tc_ticktock(int cnt) if (count < tc_tick) return; count = 0; +#else /* __rtems__ */ +void +_Timecounter_Tick(void) +{ +#endif /* __rtems__ */ tc_windup(); } +#ifdef __rtems__ +void +_Timecounter_Tick_simple(uint32_t delta, uint32_t offset) +{ + struct bintime bt; + struct timehands *th; + uint32_t ogen; + ISR_lock_Context lock_context; + + _ISR_lock_ISR_disable_and_acquire(&_Timecounter_Lock, &lock_context); + + th = timehands; + ogen = th->th_generation; + th->th_offset_count = offset; + bintime_addx(&th->th_offset, th->th_scale * delta); + + bt = th->th_offset; + bintime_add(&bt, &boottimebin); + + /* Update the UTC timestamps used by the get*() functions. */ + /* XXX shouldn't do this here. Should force non-`get' versions. */ + bintime2timeval(&bt, &th->th_microtime); + bintime2timespec(&bt, &th->th_nanotime); + + /* + * Now that the struct timehands is again consistent, set the new + * generation number, making sure to not make it zero. + */ + if (++ogen == 0) + ogen = 1; + th->th_generation = ogen; + + /* Go live with the new struct timehands. */ + time_second = th->th_microtime.tv_sec; + time_uptime = th->th_offset.sec; + + _ISR_lock_Release_and_ISR_enable(&_Timecounter_Lock, &lock_context); +} +#endif /* __rtems__ */ +#ifndef __rtems__ static void __inline tc_adjprecision(void) { @@ -1794,7 +1949,9 @@ tc_adjprecision(void) sbt_timethreshold = bttosbt(bt_timethreshold); sbt_tickthreshold = bttosbt(bt_tickthreshold); } +#endif /* __rtems__ */ +#ifndef __rtems__ static int sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS) { @@ -1811,10 +1968,17 @@ sysctl_kern_timecounter_adjprecision(SYSCTL_HANDLER_ARGS) done: return (0); } +#endif /* __rtems__ */ +#ifndef __rtems__ static void inittimecounter(void *dummy) +#else /* __rtems__ */ +void +_Timecounter_Initialize(void) +#endif /* __rtems__ */ { +#ifndef __rtems__ u_int p; int tick_rate; @@ -1838,6 +2002,7 @@ inittimecounter(void *dummy) tc_tick_sbt = bttosbt(tc_tick_bt); p = (tc_tick * 1000000) / hz; printf("Timecounters tick every %d.%03u msec\n", p / 1000, p % 1000); +#endif /* __rtems__ */ #ifdef FFCLOCK ffclock_init(); @@ -1848,8 +2013,11 @@ inittimecounter(void *dummy) tc_windup(); } +#ifndef __rtems__ SYSINIT(timecounter, SI_SUB_CLOCKS, SI_ORDER_SECOND, inittimecounter, NULL); +#endif /* __rtems__ */ +#ifndef __rtems__ /* Cpu tick handling -------------------------------------------------*/ static int cpu_tick_variable; @@ -1982,7 +2150,9 @@ cputick2usec(uint64_t tick) } cpu_tick_f *cpu_ticks = tc_cpu_ticks; +#endif /* __rtems__ */ +#ifndef __rtems__ static int vdso_th_enable = 1; static int sysctl_fast_gettime(SYSCTL_HANDLER_ARGS) @@ -2018,6 +2188,7 @@ tc_fill_vdso_timehands(struct vdso_timehands *vdso_th) enabled = 0; return (enabled); } +#endif /* __rtems__ */ #ifdef COMPAT_FREEBSD32 uint32_t -- cgit v1.2.3