blob: d6897de4f140db96ded303aaa5fea7b73e626af7 [file] [log] [blame]
Daniel Krueger9d7164c2008-12-19 11:41:57 -08001/****************************************************************************
2
3 (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4 www.systec-electronic.com
5
6 Project: openPOWERLINK
7
8 Description: target specific implementation of
9 high resolution timer module for X86 under Linux
10 The Linux kernel has to be compiled with high resolution
11 timers enabled. This is done by configuring the kernel
12 with CONFIG_HIGH_RES_TIMERS enabled.
13
14 License:
15
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
19
20 1. Redistributions of source code must retain the above copyright
21 notice, this list of conditions and the following disclaimer.
22
23 2. Redistributions in binary form must reproduce the above copyright
24 notice, this list of conditions and the following disclaimer in the
25 documentation and/or other materials provided with the distribution.
26
27 3. Neither the name of SYSTEC electronic GmbH nor the names of its
28 contributors may be used to endorse or promote products derived
29 from this software without prior written permission. For written
30 permission, please contact info@systec-electronic.com.
31
32 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
35 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
36 COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
37 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
38 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
39 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
40 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
42 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 POSSIBILITY OF SUCH DAMAGE.
44
45 Severability Clause:
46
47 If a provision of this License is or becomes illegal, invalid or
48 unenforceable in any jurisdiction, that shall not affect:
49 1. the validity or enforceability in that jurisdiction of any other
50 provision of this License; or
51 2. the validity or enforceability in other jurisdictions of that or
52 any other provision of this License.
53
54 -------------------------------------------------------------------------
55
56 $RCSfile: TimerHighReskX86.c,v $
57
58 $Author: D.Krueger $
59
60 $Revision: 1.4 $ $Date: 2008/04/17 21:38:01 $
61
62 $State: Exp $
63
64 Build Environment:
65 GNU
66
67 -------------------------------------------------------------------------
68
69 Revision History:
70
71****************************************************************************/
72
73#include "EplInc.h"
74#include "kernel/EplTimerHighResk.h"
75#include "Benchmark.h"
76
77//#include <linux/config.h>
78#include <linux/module.h>
79#include <linux/kernel.h>
80#include <linux/hrtimer.h>
81
82/***************************************************************************/
83/* */
84/* */
85/* G L O B A L D E F I N I T I O N S */
86/* */
87/* */
88/***************************************************************************/
89
90//---------------------------------------------------------------------------
91// const defines
92//---------------------------------------------------------------------------
93
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -080094#define TIMER_COUNT 2 /* max 15 timers selectable */
95#define TIMER_MIN_VAL_SINGLE 5000 /* min 5us */
96#define TIMER_MIN_VAL_CYCLE 100000 /* min 100us */
Daniel Krueger9d7164c2008-12-19 11:41:57 -080097
98#define PROVE_OVERRUN
99
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800100// TracePoint support for realtime-debugging
101#ifdef _DBG_TRACE_POINTS_
Greg Kroah-Hartman2ed53cf2009-03-23 12:36:38 -0700102void TgtDbgSignalTracePoint(u8 bTracePointNumber_p);
Greg Kroah-Hartmand539cfb2009-03-23 12:51:37 -0700103void TgtDbgPostTraceValue(u32 dwTraceValue_p);
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800104#define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
105#define TGT_DBG_POST_TRACE_VALUE(v) TgtDbgPostTraceValue(v)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800106#else
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800107#define TGT_DBG_SIGNAL_TRACE_POINT(p)
108#define TGT_DBG_POST_TRACE_VALUE(v)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800109#endif
110#define HRT_DBG_POST_TRACE_VALUE(Event_p, uiNodeId_p, wErrorCode_p) \
111 TGT_DBG_POST_TRACE_VALUE((0xE << 28) | (Event_p << 24) \
112 | (uiNodeId_p << 16) | wErrorCode_p)
113
114#define TIMERHDL_MASK 0x0FFFFFFF
115#define TIMERHDL_SHIFT 28
116#define HDL_TO_IDX(Hdl) ((Hdl >> TIMERHDL_SHIFT) - 1)
117#define HDL_INIT(Idx) ((Idx + 1) << TIMERHDL_SHIFT)
118#define HDL_INC(Hdl) (((Hdl + 1) & TIMERHDL_MASK) \
119 | (Hdl & ~TIMERHDL_MASK))
120
121//---------------------------------------------------------------------------
122// modul global types
123//---------------------------------------------------------------------------
124
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800125typedef struct {
126 tEplTimerEventArg m_EventArg;
127 tEplTimerkCallback m_pfnCallback;
128 struct hrtimer m_Timer;
129 BOOL m_fContinuously;
130 unsigned long long m_ullPeriod;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800131
132} tEplTimerHighReskTimerInfo;
133
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800134typedef struct {
135 tEplTimerHighReskTimerInfo m_aTimerInfo[TIMER_COUNT];
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800136
137} tEplTimerHighReskInstance;
138
139//---------------------------------------------------------------------------
140// local vars
141//---------------------------------------------------------------------------
142
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800143static tEplTimerHighReskInstance EplTimerHighReskInstance_l;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800144
145//---------------------------------------------------------------------------
146// local function prototypes
147//---------------------------------------------------------------------------
148
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800149enum hrtimer_restart EplTimerHighReskCallback(struct hrtimer *pTimer_p);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800150
151//=========================================================================//
152// //
153// P U B L I C F U N C T I O N S //
154// //
155//=========================================================================//
156
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800157//---------------------------------------------------------------------------
158//
159// Function: EplTimerHighReskInit()
160//
161// Description: initializes the high resolution timer module.
162//
163// Parameters: void
164//
165// Return: tEplKernel = error code
166//
167// State: not tested
168//
169//---------------------------------------------------------------------------
170
Greg Kroah-Hartmand10f4692009-03-23 10:45:12 -0700171tEplKernel EplTimerHighReskInit(void)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800172{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800173 tEplKernel Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800174
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800175 Ret = EplTimerHighReskAddInstance();
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800176
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800177 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800178
179}
180
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800181//---------------------------------------------------------------------------
182//
183// Function: EplTimerHighReskAddInstance()
184//
185// Description: initializes the high resolution timer module.
186//
187// Parameters: void
188//
189// Return: tEplKernel = error code
190//
191// State: not tested
192//
193//---------------------------------------------------------------------------
194
Greg Kroah-Hartmand10f4692009-03-23 10:45:12 -0700195tEplKernel EplTimerHighReskAddInstance(void)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800196{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800197 tEplKernel Ret;
198 unsigned int uiIndex;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800199
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800200 Ret = kEplSuccessful;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800201
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800202 EPL_MEMSET(&EplTimerHighReskInstance_l, 0,
203 sizeof(EplTimerHighReskInstance_l));
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800204
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800205 /*
206 * Initialize hrtimer structures for all usable timers.
207 */
208 for (uiIndex = 0; uiIndex < TIMER_COUNT; uiIndex++) {
209 tEplTimerHighReskTimerInfo *pTimerInfo;
210 struct hrtimer *pTimer;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800211
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800212 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
213 pTimer = &pTimerInfo->m_Timer;
214 hrtimer_init(pTimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800215
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800216 pTimer->function = EplTimerHighReskCallback;
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800217 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800218
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800219 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800220}
221
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800222//---------------------------------------------------------------------------
223//
224// Function: EplTimerHighReskDelInstance()
225//
226// Description: shuts down the high resolution timer module.
227//
228// Parameters: void
229//
230// Return: tEplKernel = error code
231//
232// State: not tested
233//
234//---------------------------------------------------------------------------
235
Greg Kroah-Hartmand10f4692009-03-23 10:45:12 -0700236tEplKernel EplTimerHighReskDelInstance(void)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800237{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800238 tEplTimerHighReskTimerInfo *pTimerInfo;
239 tEplKernel Ret;
240 unsigned int uiIndex;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800241
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800242 Ret = kEplSuccessful;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800243
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800244 for (uiIndex = 0; uiIndex < TIMER_COUNT; uiIndex++) {
245 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[0];
246 pTimerInfo->m_pfnCallback = NULL;
247 pTimerInfo->m_EventArg.m_TimerHdl = 0;
248 /*
249 * In this case we can not just try to cancel the timer.
250 * We actually have to wait until its callback function
251 * has returned.
252 */
253 hrtimer_cancel(&pTimerInfo->m_Timer);
254 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800255
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800256 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800257
258}
259
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800260//---------------------------------------------------------------------------
261//
262// Function: EplTimerHighReskModifyTimerNs()
263//
264// Description: modifies the timeout of the timer with the specified handle.
265// If the handle the pointer points to is zero, the timer must
266// be created first.
267// If it is not possible to stop the old timer,
268// this function always assures that the old timer does not
269// trigger the callback function with the same handle as the new
270// timer. That means the callback function must check the passed
271// handle with the one returned by this function. If these are
272// unequal, the call can be discarded.
273//
274// Parameters: pTimerHdl_p = pointer to timer handle
275// ullTimeNs_p = relative timeout in [ns]
276// pfnCallback_p = callback function, which is called mutual
277// exclusive with the Edrv callback functions
278// (Rx and Tx).
279// ulArgument_p = user-specific argument
280// fContinuously_p = if TRUE, callback function will be called
281// continuously;
282// otherwise, it is a oneshot timer.
283//
284// Return: tEplKernel = error code
285//
286// State: not tested
287//
288//---------------------------------------------------------------------------
289
Greg Kroah-Hartmand10f4692009-03-23 10:45:12 -0700290tEplKernel EplTimerHighReskModifyTimerNs(tEplTimerHdl *pTimerHdl_p,
291 unsigned long long ullTimeNs_p,
292 tEplTimerkCallback pfnCallback_p,
293 unsigned long ulArgument_p,
294 BOOL fContinuously_p)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800295{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800296 tEplKernel Ret;
297 unsigned int uiIndex;
298 tEplTimerHighReskTimerInfo *pTimerInfo;
299 ktime_t RelTime;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800300
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800301 Ret = kEplSuccessful;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800302
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800303 // check pointer to handle
304 if (pTimerHdl_p == NULL) {
305 Ret = kEplTimerInvalidHandle;
306 goto Exit;
307 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800308
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800309 if (*pTimerHdl_p == 0) { // no timer created yet
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800310
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800311 // search free timer info structure
312 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[0];
313 for (uiIndex = 0; uiIndex < TIMER_COUNT;
314 uiIndex++, pTimerInfo++) {
315 if (pTimerInfo->m_EventArg.m_TimerHdl == 0) { // free structure found
316 break;
317 }
318 }
319 if (uiIndex >= TIMER_COUNT) { // no free structure found
320 Ret = kEplTimerNoTimerCreated;
321 goto Exit;
322 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800323
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800324 pTimerInfo->m_EventArg.m_TimerHdl = HDL_INIT(uiIndex);
325 } else {
326 uiIndex = HDL_TO_IDX(*pTimerHdl_p);
327 if (uiIndex >= TIMER_COUNT) { // invalid handle
328 Ret = kEplTimerInvalidHandle;
329 goto Exit;
330 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800331
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800332 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
333 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800334
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800335 /*
336 * increment timer handle
337 * (if timer expires right after this statement, the user
338 * would detect an unknown timer handle and discard it)
339 */
340 pTimerInfo->m_EventArg.m_TimerHdl =
341 HDL_INC(pTimerInfo->m_EventArg.m_TimerHdl);
342 *pTimerHdl_p = pTimerInfo->m_EventArg.m_TimerHdl;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800343
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800344 // reject too small time values
345 if ((fContinuously_p && (ullTimeNs_p < TIMER_MIN_VAL_CYCLE))
346 || (!fContinuously_p && (ullTimeNs_p < TIMER_MIN_VAL_SINGLE))) {
347 Ret = kEplTimerNoTimerCreated;
348 goto Exit;
349 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800350
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800351 pTimerInfo->m_EventArg.m_ulArg = ulArgument_p;
352 pTimerInfo->m_pfnCallback = pfnCallback_p;
353 pTimerInfo->m_fContinuously = fContinuously_p;
354 pTimerInfo->m_ullPeriod = ullTimeNs_p;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800355
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800356 /*
357 * HRTIMER_MODE_REL does not influence general handling of this timer.
358 * It only sets relative mode for this start operation.
359 * -> Expire time is calculated by: Now + RelTime
360 * hrtimer_start also skips pending timer events.
361 * The state HRTIMER_STATE_CALLBACK is ignored.
362 * We have to cope with that in our callback function.
363 */
364 RelTime = ktime_add_ns(ktime_set(0, 0), ullTimeNs_p);
365 hrtimer_start(&pTimerInfo->m_Timer, RelTime, HRTIMER_MODE_REL);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800366
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800367 Exit:
368 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800369
370}
371
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800372//---------------------------------------------------------------------------
373//
374// Function: EplTimerHighReskDeleteTimer()
375//
376// Description: deletes the timer with the specified handle. Afterward the
377// handle is set to zero.
378//
379// Parameters: pTimerHdl_p = pointer to timer handle
380//
381// Return: tEplKernel = error code
382//
383// State: not tested
384//
385//---------------------------------------------------------------------------
386
Greg Kroah-Hartmand10f4692009-03-23 10:45:12 -0700387tEplKernel EplTimerHighReskDeleteTimer(tEplTimerHdl *pTimerHdl_p)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800388{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800389 tEplKernel Ret = kEplSuccessful;
390 unsigned int uiIndex;
391 tEplTimerHighReskTimerInfo *pTimerInfo;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800392
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800393 // check pointer to handle
394 if (pTimerHdl_p == NULL) {
395 Ret = kEplTimerInvalidHandle;
396 goto Exit;
397 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800398
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800399 if (*pTimerHdl_p == 0) { // no timer created yet
400 goto Exit;
401 } else {
402 uiIndex = HDL_TO_IDX(*pTimerHdl_p);
403 if (uiIndex >= TIMER_COUNT) { // invalid handle
404 Ret = kEplTimerInvalidHandle;
405 goto Exit;
406 }
407 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
408 if (pTimerInfo->m_EventArg.m_TimerHdl != *pTimerHdl_p) { // invalid handle
409 goto Exit;
410 }
411 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800412
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800413 *pTimerHdl_p = 0;
414 pTimerInfo->m_EventArg.m_TimerHdl = 0;
415 pTimerInfo->m_pfnCallback = NULL;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800416
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800417 /*
418 * Three return cases of hrtimer_try_to_cancel have to be tracked:
419 * 1 - timer has been removed
420 * 0 - timer was not active
421 * We need not do anything. hrtimer timers just consist of
422 * a hrtimer struct, which we might enqueue in the hrtimers
423 * event list by calling hrtimer_start().
424 * If a timer is not enqueued, it is not present in hrtimers.
425 * -1 - callback function is running
426 * In this case we have to ensure that the timer is not
427 * continuously restarted. This has been done by clearing
428 * its handle.
429 */
430 hrtimer_try_to_cancel(&pTimerInfo->m_Timer);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800431
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800432 Exit:
433 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800434
435}
436
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800437//---------------------------------------------------------------------------
438//
439// Function: EplTimerHighReskCallback()
440//
441// Description: Callback function commonly used for all timers.
442//
443// Parameters: pTimer_p = pointer to hrtimer
444//
445// Return:
446//
447// State: not tested
448//
449//---------------------------------------------------------------------------
450
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800451enum hrtimer_restart EplTimerHighReskCallback(struct hrtimer *pTimer_p)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800452{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800453 unsigned int uiIndex;
454 tEplTimerHighReskTimerInfo *pTimerInfo;
455 tEplTimerHdl OrgTimerHdl;
456 enum hrtimer_restart Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800457
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800458 BENCHMARK_MOD_24_SET(4);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800459
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800460 Ret = HRTIMER_NORESTART;
461 pTimerInfo =
462 container_of(pTimer_p, tEplTimerHighReskTimerInfo, m_Timer);
463 uiIndex = HDL_TO_IDX(pTimerInfo->m_EventArg.m_TimerHdl);
464 if (uiIndex >= TIMER_COUNT) { // invalid handle
465 goto Exit;
466 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800467
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800468 /*
469 * We store the timer handle before calling the callback function
470 * as the timer can be modified inside it.
471 */
472 OrgTimerHdl = pTimerInfo->m_EventArg.m_TimerHdl;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800473
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800474 if (pTimerInfo->m_pfnCallback != NULL) {
475 pTimerInfo->m_pfnCallback(&pTimerInfo->m_EventArg);
476 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800477
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800478 if (pTimerInfo->m_fContinuously) {
479 ktime_t Interval;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800480#ifdef PROVE_OVERRUN
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800481 ktime_t Now;
482 unsigned long Overruns;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800483#endif
484
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800485 if (OrgTimerHdl != pTimerInfo->m_EventArg.m_TimerHdl) {
486 /* modified timer has already been restarted */
487 goto Exit;
488 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800489#ifdef PROVE_OVERRUN
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800490 Now = ktime_get();
491 Interval =
492 ktime_add_ns(ktime_set(0, 0), pTimerInfo->m_ullPeriod);
493 Overruns = hrtimer_forward(pTimer_p, Now, Interval);
494 if (Overruns > 1) {
495 printk
496 ("EplTimerHighResk: Continuous timer (handle 0x%lX) had to skip %lu interval(s)!\n",
497 pTimerInfo->m_EventArg.m_TimerHdl, Overruns - 1);
498 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800499#else
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800500 pTimer_p->expires = ktime_add_ns(pTimer_p->expires,
501 pTimerInfo->m_ullPeriod);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800502#endif
503
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800504 Ret = HRTIMER_RESTART;
505 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800506
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800507 Exit:
508 BENCHMARK_MOD_24_RESET(4);
509 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800510}