mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-09-21 13:46:26 +08:00
timecounter: Port to RTEMS
New test sptests/timecounter01. Update #2271.
This commit is contained in:
committed by
Sebastian Huber
parent
cc6938455e
commit
31be41653a
@@ -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
|
||||
|
||||
@@ -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
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <rtems/score/timecounter.h>
|
||||
#include <rtems/score/basedefs.h>
|
||||
|
||||
#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 */
|
||||
@@ -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
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <rtems/score/timecounter.h>
|
||||
#include <rtems/score/basedefs.h>
|
||||
|
||||
#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 <rtems/timecounter.h>
|
||||
*
|
||||
* 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 */
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (c) 2015 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <rtems/timecounter.h>
|
||||
|
||||
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 );
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <sys/time.h>
|
||||
#include <sys/timetc.h>
|
||||
|
||||
#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 */
|
||||
@@ -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
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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 <rtems/score/timecounter.h>
|
||||
#include <sys/timetc.h>
|
||||
|
||||
#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 */
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <rtems/score/timecounterimpl.h>
|
||||
#endif /* __rtems__ */
|
||||
#include <sys/cdefs.h>
|
||||
__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 <sys/param.h>
|
||||
#ifndef __rtems__
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/limits.h>
|
||||
#else /* __rtems__ */
|
||||
#include <limits.h>
|
||||
#endif /* __rtems__ */
|
||||
#ifdef FFCLOCK
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
#endif
|
||||
#ifndef __rtems__
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/syslog.h>
|
||||
#include <sys/systm.h>
|
||||
#endif /* __rtems__ */
|
||||
#include <sys/timeffc.h>
|
||||
#include <sys/timepps.h>
|
||||
#include <sys/timetc.h>
|
||||
#include <sys/timex.h>
|
||||
#ifndef __rtems__
|
||||
#include <sys/vdso.h>
|
||||
#endif /* __rtems__ */
|
||||
#ifdef __rtems__
|
||||
#include <rtems.h>
|
||||
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
|
||||
|
||||
+270
-72
@@ -7,84 +7,282 @@
|
||||
|
||||
@section Introduction
|
||||
|
||||
The purpose of the clock driver is to provide a steady time
|
||||
basis to the kernel, so that the RTEMS primitives that need
|
||||
a clock tick work properly. See the @code{Clock Manager} chapter
|
||||
of the @b{RTEMS Application C User's Guide} for more details.
|
||||
The purpose of the clock driver is to provide two services for the operating
|
||||
system.
|
||||
@itemize @bullet
|
||||
@item A steady time basis to the kernel, so that the RTEMS primitives that need
|
||||
a clock tick work properly. See the @cite{Clock Manager} chapter of the
|
||||
@cite{RTEMS Application C User's Guide} for more details.
|
||||
@item An optional time counter to generate timestamps of the uptime and wall
|
||||
clock time.
|
||||
@end itemize
|
||||
|
||||
The clock driver is located in the @code{clock} directory of the BSP.
|
||||
The clock driver is usually located in the @file{clock} directory of the BSP.
|
||||
Clock drivers should use the @dfn{Clock Driver Shell} available via the
|
||||
@file{clockdrv_shell.h} include file.
|
||||
|
||||
@section Clock Driver Global Variables
|
||||
@section Clock Driver Shell
|
||||
|
||||
This section describes the global variables expected to be provided by
|
||||
this driver.
|
||||
The @dfn{Clock Driver Shell} include file defines the clock driver functions
|
||||
declared in @code{#include <rtems/clockdrv.h>} which are used by RTEMS
|
||||
configuration file @code{#include <rtems/confdefs.h>}. In case the application
|
||||
configuration defines @code{#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER},
|
||||
then the clock driver is registered and should provide its services to the
|
||||
operating system. A hardware specific clock driver must provide some
|
||||
functions, defines and macros for the @dfn{Clock Driver Shell} which are
|
||||
explained here step by step. A clock driver file looks in general like this.
|
||||
|
||||
@subsection Ticks Counter
|
||||
@example
|
||||
/*
|
||||
* A section with functions, defines and macros to provide hardware specific
|
||||
* functions for the Clock Driver Shell.
|
||||
*/
|
||||
|
||||
Most of the clock device drivers provide a global variable
|
||||
that is simply a count of the number of clock driver interrupt service
|
||||
routines that have occured. This information is valuable when debugging
|
||||
a system. This variable is declared as follows:
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
@end example
|
||||
|
||||
@subsection Initialization
|
||||
|
||||
Depending on the hardware capabilities one out of three clock driver variants
|
||||
must be selected.
|
||||
@itemize @bullet
|
||||
@item The most basic clock driver provides only a periodic interrupt service
|
||||
routine which calls @code{rtems_clock_tick()}. The interval is determined by
|
||||
the application configuration via @code{#define
|
||||
CONFIGURE_MICROSECONDS_PER_TICK} and can be obtained via
|
||||
@code{rtems_configuration_get_microseconds_per_tick()}. The timestamp
|
||||
resolution is limited to the clock tick interval.
|
||||
@item In case the hardware lacks support for a free running counter, then the
|
||||
module used for the clock tick may provide support for timestamps with a
|
||||
resolution below the clock tick interval. For this so called simple
|
||||
timecounters can be used.
|
||||
@item The desired variant uses a free running counter to provide accurate
|
||||
timestamps. This variant is mandatory on SMP configurations.
|
||||
@end itemize
|
||||
|
||||
@subsubsection Clock Tick Only Variant
|
||||
|
||||
@example
|
||||
static void some_support_initialize_hardware( void )
|
||||
@{
|
||||
/* Initialize hardware */
|
||||
@}
|
||||
|
||||
#define Clock_driver_support_initialize_hardware() \
|
||||
some_support_initialize_hardware()
|
||||
|
||||
/* Indicate that this clock driver lacks a proper timecounter in hardware */
|
||||
#define CLOCK_DRIVER_USE_DUMMY_TIMECOUNTER
|
||||
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
@end example
|
||||
|
||||
@subsubsection Simple Timecounter Variant
|
||||
|
||||
@example
|
||||
#include <rtems/timecounter.h>
|
||||
|
||||
static rtems_timecounter_simple some_tc;
|
||||
|
||||
static uint32_t some_tc_get( rtems_timecounter_simple *tc )
|
||||
@{
|
||||
return some.counter;
|
||||
@}
|
||||
|
||||
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 );
|
||||
@}
|
||||
|
||||
static void some_support_initialize_hardware( 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;
|
||||
|
||||
/* Initialize hardware */
|
||||
|
||||
rtems_timecounter_simple_install(
|
||||
&some_tc,
|
||||
frequency,
|
||||
timecounter_ticks_per_clock_tick,
|
||||
some_tc_get_timecount
|
||||
);
|
||||
@}
|
||||
|
||||
#define Clock_driver_support_initialize_hardware() \
|
||||
some_support_initialize_hardware()
|
||||
|
||||
#define Clock_driver_timecounter_tick() \
|
||||
some_tc_tick()
|
||||
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
@end example
|
||||
|
||||
@subsubsection Timecounter Variant
|
||||
|
||||
This variant is preferred since it is the most efficient and yields the most
|
||||
accurate timestamps. It is also mandatory on SMP configurations to obtain
|
||||
valid timestamps. The hardware must provide a periodic interrupt to service
|
||||
the clock tick and a free running counter for the timecounter. The free
|
||||
running counter must have a power of two period. The @code{tc_counter_mask}
|
||||
must be initialized to the free running counter period minus one, e.g. for a
|
||||
32-bit counter this is 0xffffffff. The @code{tc_get_timecount} function must
|
||||
return the current counter value (the counter values must increase, so if the
|
||||
counter counts down, a conversion is necessary). Use
|
||||
@code{RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER} for the @code{tc_quality}. Set
|
||||
@code{tc_frequency} to the frequency of the free running counter in Hz. All
|
||||
other fields of the @code{struct timecounter} must be zero initialized.
|
||||
Install the initialized timecounter via @code{rtems_timecounter_install()}.
|
||||
|
||||
@example
|
||||
#include <rtems/timecounter.h>
|
||||
|
||||
static struct timecounter some_tc;
|
||||
|
||||
static uint32_t some_tc_get_timecount( struct timecounter *tc )
|
||||
@{
|
||||
some.free_running_counter;
|
||||
@}
|
||||
|
||||
static void some_support_initialize_hardware( void )
|
||||
@{
|
||||
uint64_t us_per_tick = rtems_configuration_get_microseconds_per_tick();
|
||||
uint32_t frequency = 123456;
|
||||
|
||||
/*
|
||||
* The multiplication must be done in 64-bit arithmetic to avoid an integer
|
||||
* overflow on targets with a high enough counter frequency.
|
||||
*/
|
||||
uint32_t interval = (uint32_t) ( ( frequency * us_per_tick ) / 1000000 );
|
||||
|
||||
/*
|
||||
* Initialize hardware and set up a periodic interrupt for the configuration
|
||||
* based interval.
|
||||
*/
|
||||
|
||||
some_tc.tc_get_timecount = some_tc_get_timecount;
|
||||
some_tc.tc_counter_mask = 0xffffffff;
|
||||
some_tc.tc_frequency = frequency;
|
||||
some_tc.tc_quality = RTEMS_TIMECOUNTER_QUALITY_CLOCK_DRIVER;
|
||||
rtems_timecounter_install( &some_tc );
|
||||
@}
|
||||
|
||||
#define Clock_driver_support_initialize_hardware() \
|
||||
some_support_initialize_hardware()
|
||||
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
@end example
|
||||
|
||||
@subsection Install Clock Tick Interrupt Service Routine
|
||||
|
||||
The clock driver must provide a function to install the clock tick interrupt
|
||||
service routine via @code{Clock_driver_support_install_isr()}.
|
||||
|
||||
@example
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/fatal.h>
|
||||
|
||||
static void some_support_install_isr( rtems_interrupt_handler isr )
|
||||
@{
|
||||
rtems_status_code sc;
|
||||
|
||||
sc = rtems_interrupt_handler_install(
|
||||
SOME_IRQ,
|
||||
"Clock",
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
isr,
|
||||
NULL
|
||||
);
|
||||
if ( sc != RTEMS_SUCCESSFUL ) @{
|
||||
bsp_fatal( SOME_FATAL_IRQ_INSTALL );
|
||||
@}
|
||||
@}
|
||||
|
||||
#define Clock_driver_support_install_isr( isr, old ) \
|
||||
some_support_install_isr( isr )
|
||||
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
@end example
|
||||
|
||||
@subsection Support At Tick
|
||||
|
||||
The hardware specific support at tick is specified by
|
||||
@code{Clock_driver_support_at_tick()}.
|
||||
|
||||
@example
|
||||
static void some_support_at_tick( void )
|
||||
@{
|
||||
/* Clear interrupt */
|
||||
@}
|
||||
|
||||
#define Clock_driver_support_at_tick() \
|
||||
some_support_at_tick()
|
||||
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
@end example
|
||||
|
||||
@subsection System Shutdown Support
|
||||
|
||||
The @dfn{Clock Driver Shell} provides the routine @code{Clock_exit()} that is
|
||||
scheduled to be run during system shutdown via the @code{atexit()} routine.
|
||||
The hardware specific shutdown support is specified by
|
||||
@code{Clock_driver_support_shutdown_hardware()} which is used by
|
||||
@code{Clock_exit()}. It should disable the clock tick source if it was
|
||||
enabled. This can be used to prevent clock ticks after the system is shutdown.
|
||||
|
||||
@example
|
||||
static void some_support_shutdown_hardware( void )
|
||||
@{
|
||||
/* Shutdown hardware */
|
||||
@}
|
||||
|
||||
#define Clock_driver_support_shutdown_hardware() \
|
||||
some_support_shutdown_hardware()
|
||||
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
@end example
|
||||
|
||||
@subsection Multiple Clock Driver Ticks Per Clock Tick
|
||||
|
||||
In case the hardware needs more than one clock driver tick per clock tick (e.g.
|
||||
due to a limited range of the hardware timer), then this can be specified with
|
||||
the optional @code{#define CLOCK_DRIVER_ISRS_PER_TICK} and @code{#define
|
||||
CLOCK_DRIVER_ISRS_PER_TICK_VALUE} defines. This is currently used only for x86
|
||||
and it hopefully remains that way.
|
||||
|
||||
@example
|
||||
/* Enable multiple clock driver ticks per clock tick */
|
||||
#define CLOCK_DRIVER_ISRS_PER_TICK 1
|
||||
|
||||
/* Specifiy the clock driver ticks per clock tick value */
|
||||
#define CLOCK_DRIVER_ISRS_PER_TICK_VALUE 123
|
||||
|
||||
#include "../../../shared/clockdrv_shell.h"
|
||||
@end example
|
||||
|
||||
@subsection Clock Driver Ticks Counter
|
||||
|
||||
The @dfn{Clock Driver Shell} provide a global variable that is simply a count
|
||||
of the number of clock driver interrupt service routines that have occurred.
|
||||
This information is valuable when debugging a system. This variable is
|
||||
declared as follows:
|
||||
|
||||
@example
|
||||
volatile uint32_t Clock_driver_ticks;
|
||||
@end example
|
||||
|
||||
@section Initialization
|
||||
|
||||
The initialization routine is responsible for
|
||||
programming the hardware that will periodically
|
||||
generate an interrupt. A programmable interval timer is commonly
|
||||
used as the source of the clock tick.
|
||||
|
||||
The device should be programmed such that an interrupt is generated
|
||||
every @i{m} microseconds, where @i{m} is equal to
|
||||
@code{rtems_configuration_get_microseconds_per_tick()}. Sometimes
|
||||
the periodic interval timer can use a prescaler so you have to look
|
||||
carefully at your user's manual to determine the correct value.
|
||||
|
||||
You must use the RTEMS primitive @code{rtems_interrupt_catch} to install
|
||||
your clock interrupt service routine:
|
||||
|
||||
@example
|
||||
rtems_interrupt_catch (Clock_ISR, CLOCK_VECTOR, &old_handler);
|
||||
@end example
|
||||
|
||||
Since there is currently not a driver entry point invoked at system
|
||||
shutdown, many clock device drivers use the @code{atexit} routine
|
||||
to schedule their @code{Clock_exit} routine to execute when the
|
||||
system is shutdown.
|
||||
|
||||
By convention, many of the clock drivers do not install the clock
|
||||
tick if the @code{ticks_per_timeslice} field of the Configuration
|
||||
Table is 0.
|
||||
|
||||
@section System shutdown
|
||||
|
||||
Many drivers provide the routine @code{Clock_exit} that is scheduled
|
||||
to be run during system shutdown via the @code{atexit} routine.
|
||||
The @code{Clock_exit} routine will disable the clock tick source
|
||||
if it was enabled. This can be used to prevent clock ticks after the
|
||||
system is shutdown.
|
||||
|
||||
@section Clock Interrupt Subroutine
|
||||
|
||||
It only has to inform the kernel that a ticker has elapsed, so call :
|
||||
|
||||
@example
|
||||
@group
|
||||
rtems_isr Clock_isr( rtems_vector_number vector )
|
||||
@{
|
||||
invoke the rtems_clock_tick() directive to announce the tick
|
||||
if necessary for this hardware
|
||||
reload the programmable timer
|
||||
@}
|
||||
@end group
|
||||
@end example
|
||||
|
||||
@section IO Control
|
||||
|
||||
Prior to RTEMS 4.9, the Shared Memory MPCI Driver required a special
|
||||
IOCTL in the Clock Driver. This is no longer required and the Clock
|
||||
Driver does not have to provide an IOCTL method at all.
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ else
|
||||
_SUBDIRS += sp29
|
||||
endif
|
||||
_SUBDIRS += spintrcritical23
|
||||
_SUBDIRS += sptimecounter01
|
||||
_SUBDIRS += spatomic01
|
||||
_SUBDIRS += spintrcritical22
|
||||
_SUBDIRS += spsem03
|
||||
|
||||
@@ -41,6 +41,7 @@ AM_CONDITIONAL(HAS_SMP,test "$rtems_cv_RTEMS_SMP" = "yes")
|
||||
# Explicitly list all Makefiles here
|
||||
AC_CONFIG_FILES([Makefile
|
||||
spintrcritical23/Makefile
|
||||
sptimecounter01/Makefile
|
||||
spatomic01/Makefile
|
||||
spglobalcon01/Makefile
|
||||
spintrcritical22/Makefile
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
rtems_tests_PROGRAMS = sptimecounter01
|
||||
sptimecounter01_SOURCES = init.c
|
||||
|
||||
dist_rtems_tests_DATA = sptimecounter01.scn sptimecounter01.doc
|
||||
|
||||
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
|
||||
include $(top_srcdir)/../automake/compile.am
|
||||
include $(top_srcdir)/../automake/leaf.am
|
||||
|
||||
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
|
||||
|
||||
LINK_OBJS = $(sptimecounter01_OBJECTS)
|
||||
LINK_LIBS = $(sptimecounter01_LDLIBS)
|
||||
|
||||
sptimecounter01$(EXEEXT): $(sptimecounter01_OBJECTS) $(sptimecounter01_DEPENDENCIES)
|
||||
@rm -f sptimecounter01$(EXEEXT)
|
||||
$(make-exe)
|
||||
|
||||
include $(top_srcdir)/../automake/local.am
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
* Copyright (c) 2015 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <bsp/bootcard.h>
|
||||
|
||||
#include <rtems/test.h>
|
||||
|
||||
#include <rtems/score/timecounterimpl.h>
|
||||
#include <rtems/score/watchdogimpl.h>
|
||||
#include <rtems/timecounter.h>
|
||||
#include <rtems/bsd.h>
|
||||
|
||||
const char rtems_test_name[] = "SPTIMECOUNTER_1";
|
||||
|
||||
typedef struct {
|
||||
struct timecounter tc_soft;
|
||||
u_int tc_soft_counter;
|
||||
} test_context;
|
||||
|
||||
static test_context test_instance;
|
||||
|
||||
static uint32_t test_get_timecount_soft(struct timecounter *tc)
|
||||
{
|
||||
test_context *ctx = tc->tc_priv;
|
||||
|
||||
++ctx->tc_soft_counter;
|
||||
|
||||
return ctx->tc_soft_counter;
|
||||
}
|
||||
|
||||
void boot_card(const char *cmdline)
|
||||
{
|
||||
test_context *ctx = &test_instance;
|
||||
struct timecounter *tc_soft = &ctx->tc_soft;
|
||||
uint64_t soft_freq = 1000000;
|
||||
struct bintime bt;
|
||||
|
||||
rtems_test_begink();
|
||||
|
||||
_Timecounter_Initialize();
|
||||
_Watchdog_Handler_initialization();
|
||||
|
||||
rtems_bsd_binuptime(&bt);
|
||||
assert(bt.sec == 1);
|
||||
assert(bt.frac== 0);
|
||||
|
||||
rtems_bsd_binuptime(&bt);
|
||||
assert(bt.sec == 1);
|
||||
assert(bt.frac == 0);
|
||||
|
||||
rtems_timecounter_tick();
|
||||
rtems_bsd_binuptime(&bt);
|
||||
assert(bt.sec == 1);
|
||||
assert(bt.frac == 0);
|
||||
|
||||
ctx->tc_soft_counter = 0;
|
||||
tc_soft->tc_get_timecount = test_get_timecount_soft;
|
||||
tc_soft->tc_counter_mask = 0x0fffffff;
|
||||
tc_soft->tc_frequency = soft_freq;
|
||||
tc_soft->tc_quality = 1234;
|
||||
tc_soft->tc_priv = ctx;
|
||||
_Timecounter_Install(tc_soft);
|
||||
assert(ctx->tc_soft_counter == 3);
|
||||
|
||||
rtems_bsd_binuptime(&bt);
|
||||
assert(ctx->tc_soft_counter == 4);
|
||||
|
||||
assert(bt.sec == 1);
|
||||
assert(bt.frac == 18446744073708);
|
||||
|
||||
ctx->tc_soft_counter = 0xf0000000 | 3;
|
||||
rtems_bsd_binuptime(&bt);
|
||||
assert(ctx->tc_soft_counter == (0xf0000000 | 4));
|
||||
|
||||
assert(bt.sec == 1);
|
||||
assert(bt.frac == 18446744073708);
|
||||
|
||||
/* Ensure that the fraction overflows and the second remains constant */
|
||||
ctx->tc_soft_counter = (0xf0000000 | 3) + soft_freq;
|
||||
rtems_bsd_binuptime(&bt);
|
||||
assert(ctx->tc_soft_counter == (0xf0000000 | 4) + soft_freq);
|
||||
assert(bt.sec == 1);
|
||||
assert(bt.frac == 18446742522092);
|
||||
|
||||
rtems_test_endk();
|
||||
|
||||
_Terminate(RTEMS_FATAL_SOURCE_EXIT, false, 0);
|
||||
}
|
||||
|
||||
#define CONFIGURE_APPLICATION_DOES_NOT_NEED_CLOCK_DRIVER
|
||||
|
||||
#define CONFIGURE_APPLICATION_DISABLE_FILESYSTEM
|
||||
|
||||
#define CONFIGURE_DISABLE_NEWLIB_REENTRANCY
|
||||
|
||||
#define CONFIGURE_SCHEDULER_USER
|
||||
|
||||
#define CONFIGURE_SCHEDULER_CONTEXT
|
||||
|
||||
#define CONFIGURE_SCHEDULER_CONTROLS { }
|
||||
|
||||
#define CONFIGURE_MEMORY_PER_TASK_FOR_SCHEDULER 0
|
||||
|
||||
#define CONFIGURE_TASK_STACK_ALLOCATOR NULL
|
||||
|
||||
#define CONFIGURE_TASK_STACK_DEALLOCATOR NULL
|
||||
|
||||
#define CONFIGURE_IDLE_TASK_INITIALIZES_APPLICATION
|
||||
|
||||
#define CONFIGURE_IDLE_TASK_BODY NULL
|
||||
|
||||
#define CONFIGURE_INITIAL_EXTENSIONS RTEMS_TEST_INITIAL_EXTENSION
|
||||
|
||||
#define CONFIGURE_INIT
|
||||
|
||||
#include <rtems/confdefs.h>
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright (c) 2015 embedded brains GmbH. All rights reserved.
|
||||
*
|
||||
* embedded brains GmbH
|
||||
* Dornierstr. 4
|
||||
* 82178 Puchheim
|
||||
* Germany
|
||||
* <rtems@embedded-brains.de>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
This file describes the directives and concepts tested by this test set.
|
||||
|
||||
test set name: sptimecounter01
|
||||
|
||||
directives:
|
||||
|
||||
_Timecounter_Initialize
|
||||
rtems_timecounter_tick
|
||||
_Timecounter_Install
|
||||
rtems_bsd_bintime
|
||||
|
||||
concepts:
|
||||
|
||||
This test checks the correct functioning of the FreeBSD timecounter startup
|
||||
process
|
||||
@@ -0,0 +1,2 @@
|
||||
*** BEGIN OF TEST SPTIMECOUNTER_1 ***
|
||||
*** END OF TEST SPTIMECOUNTER_1 ***
|
||||
Reference in New Issue
Block a user