original files of m241
This commit is contained in:
@@ -0,0 +1,959 @@
|
||||
/* wvTmrLib.c - timer library (System Viewer) */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993-1995, 1998, 2004-2010, 2013, 2023
|
||||
* Wind River Systems, Inc.
|
||||
*
|
||||
* The right to copy, distribute, modify or otherwise make use
|
||||
* of this software may be licensed only pursuant to the terms
|
||||
* of an applicable Wind River license agreement.
|
||||
*/
|
||||
|
||||
/*
|
||||
modification history
|
||||
--------------------
|
||||
01y,16oct23,kch Fixed warnings when time_t is 64-bit.
|
||||
01x,30oct13,elp checked wdStart() return value.
|
||||
01w,28jan13,wzc WIND00399576 - initialize value when enabling timestamp.
|
||||
01v,06sep10,tcr Share timestamp with Cafe
|
||||
01v,15nov10,tcr Allow Cafe to use timestamp
|
||||
01u,14jun10,vhe Fixed VSB/CDF compatibility (CQ:WIND00216392); cleanup
|
||||
01t,21jan10,wzc Adapt SV to vxWorks 64bit.
|
||||
01s,27jul09,jpb Fixed compiler warning.
|
||||
01r,27aug08,jpb Renamed VSB header file
|
||||
01q,18jun08,jpb Renamed _WRS_VX_SMP to _WRS_CONFIG_SMP. Added include path
|
||||
for kernel configurations options set in vsb.
|
||||
01p,25sep07,tcr fix incorrect timestamp calculation (WIND00105916)
|
||||
01o,17sep07,tcr WIND00103129: NULL-ptr deref in traceTimestampGet() on SMP
|
||||
01n,08apr07,mmi make traceTimestampGet () SMP safe
|
||||
01m,29apr07,cjj included private/tickLibP.h for vxAbsTicks
|
||||
made pRolloverCount a volatile like vxAbsTicks
|
||||
01l,28jun06,tcr add support for POSIX trace timer: Remove i960 support
|
||||
01k,22sep05,tcr Fix SPR 112648: System Viewer wvTmrRegister() reference entry
|
||||
incorrect
|
||||
01j,20apr04,tcr change references to WindView to 'System Viewer'
|
||||
01i,05oct98,jmp doc: fixed SEE ALSO section.
|
||||
01h,28may98,dgp clean up man pages for WV 2.0 beta release
|
||||
01g,15apr98,cjtc WV2.0 i960 port
|
||||
01f,03feb95,rhp docn improvements from last printed man pages
|
||||
01e,01feb95,rhp library man page: add ref to User's Guide
|
||||
01d,05apr94,smb and more documentation changes
|
||||
01c,07mar94,smb more documentation changes
|
||||
01b,17jan94,smb documentation changes
|
||||
01a,10dec93,smb created
|
||||
*/
|
||||
|
||||
/*
|
||||
DESCRIPTION
|
||||
This library allows a Wind River System Viewer timestamp timer to be
|
||||
registered. When this timer is enabled, events are tagged with a
|
||||
timestamp as they are logged.
|
||||
|
||||
Seven routines are required for System Viewer: a timestamp routine, a timestamp
|
||||
routine that guarantees interrupt lockout, a routine that enables the timer
|
||||
driver, a routine that disables the timer driver, a routine that specifies the
|
||||
routine to run when the timer hits a rollover, a routine that returns the
|
||||
period of the timer, and a routine that returns the frequency of the
|
||||
timer.
|
||||
|
||||
|
||||
INTERNAL
|
||||
|
||||
This library now allows System Viewer, the POSIX trace system, and Cafe to
|
||||
share the timestamp driver. System Viewer requires that when the timestamp is
|
||||
connected, the rollover interrupt will be connected to the routine nominated by
|
||||
System Viewer. When POSIX trace is involved, this cannot be done directly,
|
||||
because trace needs to count rollovers.
|
||||
|
||||
When System Viever calls the connect routine, we actually connect a function in
|
||||
this library, but note the function that System Viewer requested. When the
|
||||
interrupt is handled, the function here counts the interrupt, and then passes
|
||||
control on to the function specified by System Viewer.
|
||||
|
||||
INCLUDE FILES:
|
||||
|
||||
SEE ALSO: wvLib,
|
||||
.I Wind River System Viewer User's Guide
|
||||
*/
|
||||
|
||||
/* includes */
|
||||
|
||||
#include <vxWorks.h>
|
||||
#include <vsbConfig.h>
|
||||
#include <wdLib.h>
|
||||
#include <intLib.h>
|
||||
#include <time.h>
|
||||
#include <wvTmrLib.h>
|
||||
#include <private/svFuncBindP.h>
|
||||
#include <vxAtomicLib.h>
|
||||
|
||||
/* defines */
|
||||
|
||||
#define TEN_EXP9 (1000000000L)
|
||||
|
||||
#define MAX_CLIENTS 3
|
||||
|
||||
#define WV_TMR_INDEX 0
|
||||
#define TRACE_TMR_INDEX 1
|
||||
#define CAFE_TMR_INDEX 2
|
||||
|
||||
/* typedefs */
|
||||
|
||||
/* locals */
|
||||
|
||||
LOCAL struct ts_desc ts_descs[MAX_CLIENTS];
|
||||
|
||||
LOCAL WDOG_ID rolloverWd = NULL;
|
||||
|
||||
|
||||
/* globals */
|
||||
|
||||
struct timespec traceTimerStartValue = {0,0};
|
||||
|
||||
/* forward declarations */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* localRolloverHandler - handler for all rollover interrupts
|
||||
*
|
||||
* This function uses the supplied ts_desc structure to determine which
|
||||
* timestamp has rolled over. Since a timestamp source may be shared with
|
||||
* several clients, it then calls the handlers of any client which uses the same
|
||||
* source. If the interrupt source was a watchdog, it is restarted.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL void localRolloverHandler
|
||||
(
|
||||
struct ts_desc * ts_desc
|
||||
)
|
||||
{
|
||||
int i;
|
||||
unsigned int (*ts)(void);
|
||||
/* get identification of which timestamp source */
|
||||
ts = ts_desc->ts;
|
||||
|
||||
|
||||
/* call rollover function for all enabled clients using this source */
|
||||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if (ts == ts_descs [i].ts &&
|
||||
ts_descs [i].client_handler != NULL &&
|
||||
ts_descs [i].enabled)
|
||||
{
|
||||
/* call handler */
|
||||
ts_descs [i].client_handler((_Vx_usr_arg_t)(ts_descs + i));
|
||||
}
|
||||
}
|
||||
if (ts_desc->useWd)
|
||||
(void)wdStart (rolloverWd, 1, (FUNCPTR)localRolloverHandler,
|
||||
(_Vx_usr_arg_t)ts_desc);
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* localEnable - enable a timestamp for a client
|
||||
*
|
||||
* This function enables a timestamp source for a client. If the source is
|
||||
* already enabled, then it just enables the client. Otherwise, it enables both
|
||||
* the source and client
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
LOCAL STATUS localEnable
|
||||
(
|
||||
struct ts_desc * ts /* timestamp to enable */
|
||||
)
|
||||
{
|
||||
int enabledCount = 0;
|
||||
unsigned int i;
|
||||
STATUS res = OK;
|
||||
|
||||
|
||||
if (ts->enabled)
|
||||
return OK;
|
||||
|
||||
/* count enabled clients which use the same underlying function */
|
||||
|
||||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if (ts_descs [i].ts == ts->ts &&
|
||||
ts_descs [i].enabled)
|
||||
{
|
||||
enabledCount++;
|
||||
}
|
||||
}
|
||||
|
||||
/* try not to enable a sourcce if it's already done */
|
||||
if (enabledCount == 0)
|
||||
res = ts->source_enable();
|
||||
|
||||
/* clear time stamp data */
|
||||
ts->lastRollover0 = 0;
|
||||
ts->lastRollover1 = 0;
|
||||
ts->lastTimestamp = ts->ts();
|
||||
|
||||
ts->enabled = TRUE;
|
||||
|
||||
/* if wd for this time source, start it now */
|
||||
if (ts->useWd)
|
||||
{
|
||||
if (rolloverWd == NULL)
|
||||
return ERROR;
|
||||
|
||||
res = wdStart (rolloverWd, 1, (FUNCPTR)localRolloverHandler,
|
||||
(_Vx_usr_arg_t)ts);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* localDisable - disable a timestamp for a client
|
||||
*
|
||||
* This function disables a timestamp source for a client. If the requesting
|
||||
* client is the only one for this timestamp source, then the source is disabled.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL STATUS localDisable
|
||||
(
|
||||
struct ts_desc * ts /* timestamp to disable */
|
||||
)
|
||||
{
|
||||
int enabledCount = 0;
|
||||
int wdClients = 0;
|
||||
unsigned int i;
|
||||
STATUS res = OK;
|
||||
|
||||
if (!ts->enabled)
|
||||
return OK;
|
||||
|
||||
/* count enabled clients using this source */
|
||||
for (i = 0; i < MAX_CLIENTS; i++)
|
||||
{
|
||||
if (ts_descs [i].ts == ts->ts &&
|
||||
ts_descs [i].enabled)
|
||||
{
|
||||
enabledCount++;
|
||||
|
||||
if (ts_descs [i].useWd)
|
||||
wdClients++;
|
||||
}
|
||||
}
|
||||
|
||||
if (enabledCount == 1)
|
||||
res = ts->source_disable();
|
||||
|
||||
ts->enabled = FALSE;
|
||||
|
||||
if (!ts->useWd)
|
||||
return res;
|
||||
|
||||
/* client uses watchdog: If there are no others, using it, cancel it */
|
||||
if (wdClients == 1)
|
||||
{
|
||||
if (rolloverWd == NULL)
|
||||
return ERROR;
|
||||
|
||||
wdCancel (rolloverWd);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* localWvEnable - enable a timestamp for System Viewer
|
||||
*
|
||||
* This function enables a previously-registered timestamp source for System
|
||||
* Viewer.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL void localWvEnable (void)
|
||||
{
|
||||
localEnable (ts_descs + WV_TMR_INDEX);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* localWvDisable - diable a timestamp for System Viewer
|
||||
*
|
||||
* This function disables a previously-registered timestamp source for a System
|
||||
* Viewer.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL void localWvDisable (void)
|
||||
{
|
||||
localDisable (ts_descs + WV_TMR_INDEX);
|
||||
}
|
||||
|
||||
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* localCafeEnable - enable a timestamp for Cafe
|
||||
*
|
||||
* This function enables a previously-registered timestamp source for Cafe
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL void localCafeEnable (void)
|
||||
{
|
||||
localEnable (ts_descs + CAFE_TMR_INDEX);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* localCafeDisable - disable a timestamp for Cafe
|
||||
*
|
||||
* This function disables a previously-registered timestamp source for Cafe
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL void localCafeDisable (void)
|
||||
{
|
||||
localDisable (ts_descs + CAFE_TMR_INDEX);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* traceTmrMuxEnable - enable a timestamp for POSIX trace
|
||||
*
|
||||
* This function enables a previously-registered timestamp source for POSIX
|
||||
* tracing
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
void traceTmrMuxEnable (void)
|
||||
{
|
||||
localEnable (ts_descs + TRACE_TMR_INDEX);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* traceTmrMuxDisable - disable a timestamp for POSIX trace
|
||||
*
|
||||
* This function disables a previously-registered timestamp source for POSIX
|
||||
* tracing
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
void traceTmrMuxDisable (void)
|
||||
{
|
||||
localDisable (ts_descs + TRACE_TMR_INDEX);
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* localConnect - connect a rollover handler for a client
|
||||
*
|
||||
* This function is called by a client to attach a handler, which will be called
|
||||
* later when a timestamp rolls over. It notes the requested handler in the
|
||||
* supplied ts_desc structure, and connects the local handler.
|
||||
*
|
||||
* It returns the result of calling the rollover connect function for the
|
||||
* requested timestamp.
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL STATUS localConnect
|
||||
(
|
||||
void (*client_handler)(_Vx_usr_arg_t),
|
||||
struct ts_desc * ts
|
||||
)
|
||||
{
|
||||
STATUS result;
|
||||
|
||||
ts->client_handler = client_handler;
|
||||
ts->useWd = FALSE;
|
||||
|
||||
/* interrupt will call nominated local function with ts_desc */
|
||||
result = ts->source_connect((void (*)(_Vx_usr_arg_t))localRolloverHandler,
|
||||
(_Vx_usr_arg_t)ts);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* wvRolloverConnect - connect a rollover handler for System Viewer
|
||||
*
|
||||
* This function attempts to connect a rollover handler to the System Viewer
|
||||
* timestamp source
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL STATUS wvRolloverConnect
|
||||
(
|
||||
void (*handler)(_Vx_usr_arg_t),
|
||||
struct ts_desc *ts
|
||||
)
|
||||
{
|
||||
STATUS res;
|
||||
|
||||
res = localConnect(handler, ts_descs + WV_TMR_INDEX);
|
||||
if (res == ERROR)
|
||||
ts_descs [WV_TMR_INDEX].client_handler = NULL;
|
||||
return res;
|
||||
|
||||
}
|
||||
#endif /* _WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* rolloverHandler - count rollover for a timestamp source
|
||||
*
|
||||
* This function records a rollover for a client
|
||||
*
|
||||
* RETURNS: OK or ERROR
|
||||
*
|
||||
* \NOMANUAL
|
||||
*
|
||||
*/
|
||||
|
||||
LOCAL void rolloverHandler
|
||||
(
|
||||
_Vx_usr_arg_t arg
|
||||
)
|
||||
{
|
||||
struct ts_desc * ts = (struct ts_desc *)arg;
|
||||
unsigned int p = ts->period ();
|
||||
int key = INT_CPU_LOCK ();
|
||||
|
||||
ts->lastRollover0 += p;
|
||||
ts->lastTimestamp = ts->ts();
|
||||
|
||||
/* ensure both lastRollover0 and lastTimestamp have been updated */
|
||||
VX_MEM_BARRIER_RW();
|
||||
|
||||
ts->lastRollover1 += p;
|
||||
|
||||
INT_CPU_UNLOCK (key);
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WRS_CONFIG_SV_INSTRUMENTATION
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* wvTmrRegister - register a timestamp timer
|
||||
*
|
||||
* This routine registers a timestamp routine for each of the following:
|
||||
* .iP <wvTmrRtn>
|
||||
* a timestamp routine, which returns a timestamp when called (must be called
|
||||
* with interrupts locked).
|
||||
* .iP <wvTmrLockRtn>
|
||||
* a timestamp routine, which returns a timestamp when called (locks interrupts).
|
||||
* .iP <wvTmrEnable>
|
||||
* an enable-timer routine, which enables the timestamp timer.
|
||||
* .iP <wvTmrDisable>
|
||||
* a disable-timer routine, which disables the timestamp timer.
|
||||
* .iP <wvTmrConnect>
|
||||
* a connect-to-timer routine, which connects a handler to be run when the timer
|
||||
* rolls over; this routine should return ERROR if the system clock tick is to be
|
||||
* used.
|
||||
* .iP <wvTmrPeriod>
|
||||
* a period-of-timer routine, which returns the period of the timer.
|
||||
* .iP <wvTmrFreq>
|
||||
* a frequency-of-timer routine, which returns the frequency of the timer.
|
||||
* .LP
|
||||
*
|
||||
* If any of these routines is set to NULL, the behavior of instrumented code
|
||||
* is undefined.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO:
|
||||
*/
|
||||
|
||||
void wvTmrRegister
|
||||
(
|
||||
UINTFUNCPTR wvTmrRtn, /* timestamp function */
|
||||
UINTFUNCPTR wvTmrLockRtn, /* int-locked timestamp function */
|
||||
FUNCPTR wvTmrEnable, /* enable timestamp */
|
||||
FUNCPTR wvTmrDisable, /* disable timestamp */
|
||||
FUNCPTR wvTmrConnect, /* connect rollover */
|
||||
UINTFUNCPTR wvTmrPeriod, /* period of timestamp */
|
||||
UINTFUNCPTR wvTmrFreq /* frequency of timestamp */
|
||||
)
|
||||
{
|
||||
ts_descs [WV_TMR_INDEX].ts = wvTmrRtn;
|
||||
ts_descs [WV_TMR_INDEX].tsLock = wvTmrLockRtn;
|
||||
ts_descs [WV_TMR_INDEX].source_enable = wvTmrEnable;
|
||||
ts_descs [WV_TMR_INDEX].source_disable = wvTmrDisable;
|
||||
ts_descs [WV_TMR_INDEX].period = wvTmrPeriod;
|
||||
ts_descs [WV_TMR_INDEX].frequency = wvTmrFreq;
|
||||
ts_descs [WV_TMR_INDEX].source_connect = wvTmrConnect;
|
||||
|
||||
ts_descs [WV_TMR_INDEX].enable = (FUNCPTR)localWvEnable;
|
||||
ts_descs [WV_TMR_INDEX].disable = (FUNCPTR)localWvDisable;
|
||||
ts_descs [WV_TMR_INDEX].connect = (FUNCPTR)wvRolloverConnect;
|
||||
|
||||
ts_descs [WV_TMR_INDEX].enabled = FALSE;
|
||||
|
||||
if (rolloverWd == NULL)
|
||||
rolloverWd = wdCreate ();
|
||||
|
||||
/*
|
||||
use our rollover connect function, having saved the one the client
|
||||
requested into source_connect
|
||||
*/
|
||||
|
||||
_func_tmrConnect = (FUNCPTR)wvRolloverConnect;
|
||||
|
||||
/* because this is WV tmr, connect to global funcptrs */
|
||||
|
||||
_func_tmrDisable = localWvDisable;
|
||||
_func_tmrEnable = localWvEnable;
|
||||
_func_tmrFreq = (FUNCPTR)wvTmrFreq;
|
||||
_func_tmrPeriod = (FUNCPTR)wvTmrPeriod;
|
||||
_func_tmrStamp = (FUNCPTR)wvTmrRtn;
|
||||
_func_tmrStampLock = (FUNCPTR)wvTmrLockRtn;
|
||||
|
||||
}
|
||||
|
||||
#endif /*_WRS_CONFIG_SV_INSTRUMENTATION */
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* cafeTmrRegister - register a timestamp driver for Cafe analysis system
|
||||
*
|
||||
* This routine registers a timestamp routine for each of the following:
|
||||
*
|
||||
* .iP <tmrRtn>
|
||||
* a timestamp routine, which returns a timestamp when called
|
||||
* .iP <tmrLockRtn>
|
||||
* a timestamp routine, which returns a timestamp when called. Interrupts are
|
||||
* lockded while the timestamp is read
|
||||
* .iP <tmrEnable>
|
||||
* an enable-timer routine, which enables the timestamp timer.
|
||||
* .iP <tmrDisable>
|
||||
* a disable-timer routine, which disables the timestamp timer.
|
||||
* .iP <tmrConnect>
|
||||
* a connect-to-timer routine, which connects a handler to be run when the timer
|
||||
* rolls over; this routine should return ERROR if the system clock tick is to be
|
||||
* used.
|
||||
* .iP <tmrPeriod>
|
||||
* a period-of-timer routine, which returns the period of the timer.
|
||||
* .iP <tmrFreq>
|
||||
* a frequency-of-timer routine, which returns the frequency of the timer.
|
||||
* .LP
|
||||
*
|
||||
* If any of these routines is set to NULL, the behavior of instrumented code
|
||||
* is undefined.
|
||||
*
|
||||
* RETURNS: Pointer to TS_DESC structure containing cached function pointers and
|
||||
* values used by timestamp functions for Cafe
|
||||
*
|
||||
* ERRNO:
|
||||
*
|
||||
*/
|
||||
|
||||
TS_DESC * cafeTmrRegister
|
||||
(
|
||||
UINTFUNCPTR tmrRtn, /* timestamp function */
|
||||
UINTFUNCPTR tmrLockRtn, /* int-locked timestamp function */
|
||||
FUNCPTR tmrEnable, /* enable timestamp */
|
||||
FUNCPTR tmrDisable, /* disable timestamp */
|
||||
FUNCPTR tmrConnect, /* connect rollover */
|
||||
UINTFUNCPTR tmrPeriod, /* period of timestamp */
|
||||
UINTFUNCPTR tmrFreq /* frequency of timestamp */
|
||||
)
|
||||
{
|
||||
ts_descs [CAFE_TMR_INDEX].ts = tmrRtn;
|
||||
ts_descs [CAFE_TMR_INDEX].tsLock = tmrLockRtn;
|
||||
ts_descs [CAFE_TMR_INDEX].source_enable = tmrEnable;
|
||||
ts_descs [CAFE_TMR_INDEX].source_disable = tmrDisable;
|
||||
ts_descs [CAFE_TMR_INDEX].period = tmrPeriod;
|
||||
ts_descs [CAFE_TMR_INDEX].frequency = tmrFreq;
|
||||
ts_descs [CAFE_TMR_INDEX].source_connect = tmrConnect;
|
||||
|
||||
ts_descs [CAFE_TMR_INDEX].enable = (FUNCPTR)localCafeEnable;
|
||||
ts_descs [CAFE_TMR_INDEX].disable = (FUNCPTR)localCafeDisable;
|
||||
ts_descs [CAFE_TMR_INDEX].connect = NULL; /* no external rollover handler */
|
||||
|
||||
if (rolloverWd == NULL)
|
||||
rolloverWd = wdCreate ();
|
||||
|
||||
if (localConnect (rolloverHandler, ts_descs + CAFE_TMR_INDEX) != OK)
|
||||
{
|
||||
/* source uses sysClk as rollover */
|
||||
ts_descs [CAFE_TMR_INDEX].useWd = TRUE;
|
||||
}
|
||||
|
||||
return ts_descs + CAFE_TMR_INDEX;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* traceTmrRegister - register a timestamp driver for POSIX trace
|
||||
*
|
||||
* This routine registers a timestamp routine for each of the following:
|
||||
*
|
||||
* .iP <traceTmrRtn>
|
||||
* a timestamp routine, which returns a timestamp when called (must be called
|
||||
* with interrupts locked).
|
||||
* .iP <traceTmrEnable>
|
||||
* an enable-timer routine, which enables the timestamp timer.
|
||||
* .iP <traceTmrDisable>
|
||||
* a disable-timer routine, which disables the timestamp timer.
|
||||
* .iP <traceTmrConnect>
|
||||
* a connect-to-timer routine, which connects a handler to be run when the timer
|
||||
* rolls over; this routine should return ERROR if the system clock tick is to be
|
||||
* used.
|
||||
* .iP <traceTmrPeriod>
|
||||
* a period-of-timer routine, which returns the period of the timer.
|
||||
* .iP <traceTmrFreq>
|
||||
* a frequency-of-timer routine, which returns the frequency of the timer.
|
||||
* .LP
|
||||
*
|
||||
* If any of these routines is set to NULL, the behavior of instrumented code
|
||||
* is undefined.
|
||||
*
|
||||
* RETURNS: N/A
|
||||
*
|
||||
* ERRNO:
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
void traceTmrRegister
|
||||
(
|
||||
UINTFUNCPTR tmrRtn,
|
||||
FUNCPTR tmrEnable,
|
||||
FUNCPTR tmrDisable,
|
||||
FUNCPTR tmrConnect,
|
||||
UINTFUNCPTR tmrPeriod,
|
||||
UINTFUNCPTR tmrFreq
|
||||
)
|
||||
{
|
||||
ts_descs [TRACE_TMR_INDEX].ts = tmrRtn;
|
||||
ts_descs [TRACE_TMR_INDEX].tsLock = tmrRtn;
|
||||
ts_descs [TRACE_TMR_INDEX].source_enable = tmrEnable;
|
||||
ts_descs [TRACE_TMR_INDEX].source_disable = tmrDisable;
|
||||
ts_descs [TRACE_TMR_INDEX].period = tmrPeriod;
|
||||
ts_descs [TRACE_TMR_INDEX].frequency = tmrFreq;
|
||||
ts_descs [TRACE_TMR_INDEX].source_connect = tmrConnect;
|
||||
|
||||
ts_descs [TRACE_TMR_INDEX].enabled = FALSE;
|
||||
|
||||
ts_descs [TRACE_TMR_INDEX].enable = (FUNCPTR)traceTmrMuxEnable;
|
||||
ts_descs [TRACE_TMR_INDEX].disable = (FUNCPTR)traceTmrMuxDisable;
|
||||
ts_descs [TRACE_TMR_INDEX].connect = NULL; /* no external rollover handler */
|
||||
|
||||
if (rolloverWd == NULL)
|
||||
rolloverWd = wdCreate ();
|
||||
|
||||
if (localConnect (rolloverHandler, ts_descs + TRACE_TMR_INDEX) != OK)
|
||||
{
|
||||
/* source uses sysClk as rollover */
|
||||
ts_descs [TRACE_TMR_INDEX].useWd = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* ticksToTime - convert system-specific time to struct timespec
|
||||
*
|
||||
* This function takes system clock ticks, and the high-res timer value, and
|
||||
* converts to seconds and nanoseconds. It also applies an offset, which could be
|
||||
* derived from time-of-day at system startup
|
||||
*
|
||||
* \INTERNAL
|
||||
* The nowTicks variable (64bit) will contain the time since boot, in units of the
|
||||
* high-resolution clock, so it's a bit like the Intel TSC. At a clockrate
|
||||
* of (say) 4GHz, it will overflow in 146 years.
|
||||
*
|
||||
* \NOMANUAL
|
||||
*/
|
||||
|
||||
LOCAL STATUS ticksToTime
|
||||
(
|
||||
UINT64 ticks, /* extended tick count */
|
||||
struct ts_desc * ts_desc, /* timestamp selection */
|
||||
const struct timespec * offset, /* offset */
|
||||
struct timespec * now /* result */
|
||||
)
|
||||
{
|
||||
UINT64 nowTicks; /* timestamp in clock ticks */
|
||||
UINT64 nowFracSec; /* fraction of second, high-res ticks */
|
||||
|
||||
UINT32 tsFreq;
|
||||
UINT32 tsPeriod;
|
||||
|
||||
tsFreq = ts_desc->frequency ();
|
||||
tsPeriod = ts_desc->period ();
|
||||
|
||||
now->tv_sec = (time_t) (ticks / tsFreq);
|
||||
|
||||
nowFracSec = ticks % tsFreq;
|
||||
|
||||
/* Convert from ticks to nsec */
|
||||
|
||||
now->tv_nsec = (long) (nowFracSec * TEN_EXP9 / tsFreq);
|
||||
|
||||
now->tv_sec += offset->tv_sec;
|
||||
now->tv_nsec += offset->tv_nsec;
|
||||
|
||||
while (now->tv_nsec >= TEN_EXP9)
|
||||
{
|
||||
now->tv_nsec -= TEN_EXP9;
|
||||
now->tv_sec++;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* wvTmrTimestamp64ToTime - convert system-specific time to struct timespec
|
||||
*
|
||||
* This function converts a 64bit timestamp into struct timespec
|
||||
*
|
||||
*/
|
||||
|
||||
STATUS wvTmrTimestamp64ToTime
|
||||
(
|
||||
UINT64 ticks, /* extended tick count */
|
||||
struct ts_desc * ts_desc, /* timestamp selection */
|
||||
struct timespec * now /* result */
|
||||
)
|
||||
{
|
||||
struct timespec offset = {0,0};
|
||||
|
||||
return (ticksToTime (ticks, ts_desc, &offset, now));
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* wvTmrTimestamp64Get - get an extended timestamp
|
||||
*
|
||||
* This function reads a 64bit timestamp from the requested timestamp source
|
||||
*
|
||||
* RETURNS: OK ,or ERROR
|
||||
*
|
||||
*/
|
||||
|
||||
STATUS wvTmrTimestamp64Get
|
||||
(
|
||||
TS_DESC * ts, /* timestamp to get timestamp from */
|
||||
unsigned long long * result /* 64bit timestamp result */
|
||||
)
|
||||
{
|
||||
unsigned long long rollover0;
|
||||
unsigned long long rollover1;
|
||||
unsigned int timestamp;
|
||||
unsigned int timestampSave;
|
||||
|
||||
if (ts == NULL)
|
||||
return ERROR;
|
||||
|
||||
do
|
||||
{
|
||||
rollover0 = ts->lastRollover0;
|
||||
timestampSave = ts->lastTimestamp;
|
||||
timestamp = ts->ts();
|
||||
|
||||
rollover1 = ts->lastRollover1;
|
||||
} while (rollover0 != rollover1);
|
||||
|
||||
if (timestamp < timestampSave)
|
||||
rollover0 += ts->period();
|
||||
|
||||
*result = rollover0 + timestamp;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* wvTmrFrequency64Get - get timestamp frequency
|
||||
*
|
||||
* This function retrieves 64bit frequency from the requested timestamp source
|
||||
*
|
||||
* RETURNS: OK ,or ERROR
|
||||
*
|
||||
*/
|
||||
|
||||
STATUS wvTmrFrequency64Get
|
||||
(
|
||||
TS_DESC * ts, /* timestamp to get timestamp from */
|
||||
unsigned long long * result /* 64bit frequency result */
|
||||
)
|
||||
{
|
||||
if (ts == NULL)
|
||||
return ERROR;
|
||||
|
||||
*result = ts->frequency();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* wvTmrEnable - enable timestamp source
|
||||
*
|
||||
* This function enables the source of the timestamp
|
||||
*
|
||||
* RETURNS: OK ,or ERROR
|
||||
*
|
||||
*/
|
||||
|
||||
STATUS wvTmrEnable
|
||||
(
|
||||
TS_DESC * ts /* timestamp to enable */
|
||||
)
|
||||
{
|
||||
if (ts == NULL)
|
||||
return ERROR;
|
||||
|
||||
return ts->enable();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* wvTmrDisable - disable timestamp source
|
||||
*
|
||||
* This function disables the source of the timestamp
|
||||
*
|
||||
* RETURNS: OK ,or ERROR
|
||||
*
|
||||
*/
|
||||
|
||||
STATUS wvTmrDisable
|
||||
(
|
||||
TS_DESC * ts /* timestamp to enable */
|
||||
)
|
||||
{
|
||||
if (ts == NULL)
|
||||
return ERROR;
|
||||
|
||||
return ts->disable();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* traceTimestampGet - get a timestamp in 'struct timespec' form
|
||||
*
|
||||
* This function uses the timestamp driver and the tick count to get the time
|
||||
*
|
||||
* The timestamp driver provides high resolution, but the result has to be
|
||||
* normalised. To do this we use the timestamp frequency and period, and the
|
||||
* number of times the counter has rolled over since startup.
|
||||
* The frequency and period are known from the driver, the number of rollovers is
|
||||
* updated during the rollover interrupt.
|
||||
*
|
||||
* NOMANUAL
|
||||
*/
|
||||
|
||||
STATUS traceTimestampGet
|
||||
(
|
||||
struct timespec * pTimestamp /* destination for timestamp */
|
||||
)
|
||||
{
|
||||
unsigned long long tmrTimestamp;
|
||||
|
||||
if (wvTmrTimestamp64Get (ts_descs + TRACE_TMR_INDEX,
|
||||
&tmrTimestamp) != OK)
|
||||
return ERROR;
|
||||
|
||||
ticksToTime (tmrTimestamp, ts_descs + TRACE_TMR_INDEX,
|
||||
&traceTimerStartValue, pTimestamp);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
*
|
||||
* traceTmrResolutionGet - get resolution of timestamp source, in nanoseconds
|
||||
*
|
||||
* Write the resolution of the timestamp source into the supplied timespec. If
|
||||
* the timestamp resolution cannot be obtained (maybe the timestamp driver is not
|
||||
* available) then the timespec structure will be filled with zeroes.
|
||||
*
|
||||
* RETURNS: OK, or ERROR.
|
||||
*
|
||||
*/
|
||||
|
||||
STATUS traceTmrResolutionGet
|
||||
(
|
||||
struct timespec * pTimestamp /* destination for resolution */
|
||||
)
|
||||
{
|
||||
UINT32 freq;
|
||||
long resolution;
|
||||
int result = OK;
|
||||
|
||||
if (ts_descs [TRACE_TMR_INDEX].frequency != NULL)
|
||||
{
|
||||
freq = (ts_descs [TRACE_TMR_INDEX].frequency)();
|
||||
|
||||
resolution = TEN_EXP9 / freq;
|
||||
|
||||
pTimestamp->tv_nsec = resolution % TEN_EXP9;
|
||||
pTimestamp->tv_sec = resolution / TEN_EXP9;
|
||||
}
|
||||
else
|
||||
{
|
||||
pTimestamp->tv_nsec = 0;
|
||||
pTimestamp->tv_sec = 0;
|
||||
|
||||
result = ERROR;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
Reference in New Issue
Block a user