blob: 82eee4702aa67b7a80e412aada765cae2ddc2fb1 [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#ifndef CONFIG_HIGH_RES_TIMERS
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800101#error "Kernel symbol CONFIG_HIGH_RES_TIMERS is required."
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800102#endif
103
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800104// TracePoint support for realtime-debugging
105#ifdef _DBG_TRACE_POINTS_
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800106void PUBLIC TgtDbgSignalTracePoint(BYTE bTracePointNumber_p);
107void PUBLIC TgtDbgPostTraceValue(DWORD dwTraceValue_p);
108#define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
109#define TGT_DBG_POST_TRACE_VALUE(v) TgtDbgPostTraceValue(v)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800110#else
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800111#define TGT_DBG_SIGNAL_TRACE_POINT(p)
112#define TGT_DBG_POST_TRACE_VALUE(v)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800113#endif
114#define HRT_DBG_POST_TRACE_VALUE(Event_p, uiNodeId_p, wErrorCode_p) \
115 TGT_DBG_POST_TRACE_VALUE((0xE << 28) | (Event_p << 24) \
116 | (uiNodeId_p << 16) | wErrorCode_p)
117
118#define TIMERHDL_MASK 0x0FFFFFFF
119#define TIMERHDL_SHIFT 28
120#define HDL_TO_IDX(Hdl) ((Hdl >> TIMERHDL_SHIFT) - 1)
121#define HDL_INIT(Idx) ((Idx + 1) << TIMERHDL_SHIFT)
122#define HDL_INC(Hdl) (((Hdl + 1) & TIMERHDL_MASK) \
123 | (Hdl & ~TIMERHDL_MASK))
124
125//---------------------------------------------------------------------------
126// modul global types
127//---------------------------------------------------------------------------
128
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800129typedef struct {
130 tEplTimerEventArg m_EventArg;
131 tEplTimerkCallback m_pfnCallback;
132 struct hrtimer m_Timer;
133 BOOL m_fContinuously;
134 unsigned long long m_ullPeriod;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800135
136} tEplTimerHighReskTimerInfo;
137
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800138typedef struct {
139 tEplTimerHighReskTimerInfo m_aTimerInfo[TIMER_COUNT];
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800140
141} tEplTimerHighReskInstance;
142
143//---------------------------------------------------------------------------
144// local vars
145//---------------------------------------------------------------------------
146
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800147static tEplTimerHighReskInstance EplTimerHighReskInstance_l;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800148
149//---------------------------------------------------------------------------
150// local function prototypes
151//---------------------------------------------------------------------------
152
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800153enum hrtimer_restart EplTimerHighReskCallback(struct hrtimer *pTimer_p);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800154
155//=========================================================================//
156// //
157// P U B L I C F U N C T I O N S //
158// //
159//=========================================================================//
160
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800161//---------------------------------------------------------------------------
162//
163// Function: EplTimerHighReskInit()
164//
165// Description: initializes the high resolution timer module.
166//
167// Parameters: void
168//
169// Return: tEplKernel = error code
170//
171// State: not tested
172//
173//---------------------------------------------------------------------------
174
175tEplKernel PUBLIC EplTimerHighReskInit(void)
176{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800177 tEplKernel Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800178
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800179 Ret = EplTimerHighReskAddInstance();
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800180
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800181 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800182
183}
184
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800185//---------------------------------------------------------------------------
186//
187// Function: EplTimerHighReskAddInstance()
188//
189// Description: initializes the high resolution timer module.
190//
191// Parameters: void
192//
193// Return: tEplKernel = error code
194//
195// State: not tested
196//
197//---------------------------------------------------------------------------
198
199tEplKernel PUBLIC EplTimerHighReskAddInstance(void)
200{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800201 tEplKernel Ret;
202 unsigned int uiIndex;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800203
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800204 Ret = kEplSuccessful;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800205
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800206 EPL_MEMSET(&EplTimerHighReskInstance_l, 0,
207 sizeof(EplTimerHighReskInstance_l));
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800208
209#ifndef CONFIG_HIGH_RES_TIMERS
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800210 printk
211 ("EplTimerHighResk: Kernel symbol CONFIG_HIGH_RES_TIMERS is required.\n");
212 Ret = kEplNoResource;
213 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800214#endif
215
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800216 /*
217 * Initialize hrtimer structures for all usable timers.
218 */
219 for (uiIndex = 0; uiIndex < TIMER_COUNT; uiIndex++) {
220 tEplTimerHighReskTimerInfo *pTimerInfo;
221 struct hrtimer *pTimer;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800222
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800223 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
224 pTimer = &pTimerInfo->m_Timer;
225 hrtimer_init(pTimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800226
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800227 pTimer->function = EplTimerHighReskCallback;
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800228 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800229
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800230 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800231}
232
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800233//---------------------------------------------------------------------------
234//
235// Function: EplTimerHighReskDelInstance()
236//
237// Description: shuts down the high resolution timer module.
238//
239// Parameters: void
240//
241// Return: tEplKernel = error code
242//
243// State: not tested
244//
245//---------------------------------------------------------------------------
246
247tEplKernel PUBLIC EplTimerHighReskDelInstance(void)
248{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800249 tEplTimerHighReskTimerInfo *pTimerInfo;
250 tEplKernel Ret;
251 unsigned int uiIndex;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800252
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800253 Ret = kEplSuccessful;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800254
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800255 for (uiIndex = 0; uiIndex < TIMER_COUNT; uiIndex++) {
256 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[0];
257 pTimerInfo->m_pfnCallback = NULL;
258 pTimerInfo->m_EventArg.m_TimerHdl = 0;
259 /*
260 * In this case we can not just try to cancel the timer.
261 * We actually have to wait until its callback function
262 * has returned.
263 */
264 hrtimer_cancel(&pTimerInfo->m_Timer);
265 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800266
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800267 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800268
269}
270
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800271//---------------------------------------------------------------------------
272//
273// Function: EplTimerHighReskModifyTimerNs()
274//
275// Description: modifies the timeout of the timer with the specified handle.
276// If the handle the pointer points to is zero, the timer must
277// be created first.
278// If it is not possible to stop the old timer,
279// this function always assures that the old timer does not
280// trigger the callback function with the same handle as the new
281// timer. That means the callback function must check the passed
282// handle with the one returned by this function. If these are
283// unequal, the call can be discarded.
284//
285// Parameters: pTimerHdl_p = pointer to timer handle
286// ullTimeNs_p = relative timeout in [ns]
287// pfnCallback_p = callback function, which is called mutual
288// exclusive with the Edrv callback functions
289// (Rx and Tx).
290// ulArgument_p = user-specific argument
291// fContinuously_p = if TRUE, callback function will be called
292// continuously;
293// otherwise, it is a oneshot timer.
294//
295// Return: tEplKernel = error code
296//
297// State: not tested
298//
299//---------------------------------------------------------------------------
300
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800301tEplKernel PUBLIC EplTimerHighReskModifyTimerNs(tEplTimerHdl * pTimerHdl_p,
302 unsigned long long ullTimeNs_p,
303 tEplTimerkCallback
304 pfnCallback_p,
305 unsigned long ulArgument_p,
306 BOOL fContinuously_p)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800307{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800308 tEplKernel Ret;
309 unsigned int uiIndex;
310 tEplTimerHighReskTimerInfo *pTimerInfo;
311 ktime_t RelTime;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800312
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800313 Ret = kEplSuccessful;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800314
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800315 // check pointer to handle
316 if (pTimerHdl_p == NULL) {
317 Ret = kEplTimerInvalidHandle;
318 goto Exit;
319 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800320
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800321 if (*pTimerHdl_p == 0) { // no timer created yet
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800322
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800323 // search free timer info structure
324 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[0];
325 for (uiIndex = 0; uiIndex < TIMER_COUNT;
326 uiIndex++, pTimerInfo++) {
327 if (pTimerInfo->m_EventArg.m_TimerHdl == 0) { // free structure found
328 break;
329 }
330 }
331 if (uiIndex >= TIMER_COUNT) { // no free structure found
332 Ret = kEplTimerNoTimerCreated;
333 goto Exit;
334 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800335
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800336 pTimerInfo->m_EventArg.m_TimerHdl = HDL_INIT(uiIndex);
337 } else {
338 uiIndex = HDL_TO_IDX(*pTimerHdl_p);
339 if (uiIndex >= TIMER_COUNT) { // invalid handle
340 Ret = kEplTimerInvalidHandle;
341 goto Exit;
342 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800343
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800344 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
345 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800346
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800347 /*
348 * increment timer handle
349 * (if timer expires right after this statement, the user
350 * would detect an unknown timer handle and discard it)
351 */
352 pTimerInfo->m_EventArg.m_TimerHdl =
353 HDL_INC(pTimerInfo->m_EventArg.m_TimerHdl);
354 *pTimerHdl_p = pTimerInfo->m_EventArg.m_TimerHdl;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800355
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800356 // reject too small time values
357 if ((fContinuously_p && (ullTimeNs_p < TIMER_MIN_VAL_CYCLE))
358 || (!fContinuously_p && (ullTimeNs_p < TIMER_MIN_VAL_SINGLE))) {
359 Ret = kEplTimerNoTimerCreated;
360 goto Exit;
361 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800362
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800363 pTimerInfo->m_EventArg.m_ulArg = ulArgument_p;
364 pTimerInfo->m_pfnCallback = pfnCallback_p;
365 pTimerInfo->m_fContinuously = fContinuously_p;
366 pTimerInfo->m_ullPeriod = ullTimeNs_p;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800367
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800368 /*
369 * HRTIMER_MODE_REL does not influence general handling of this timer.
370 * It only sets relative mode for this start operation.
371 * -> Expire time is calculated by: Now + RelTime
372 * hrtimer_start also skips pending timer events.
373 * The state HRTIMER_STATE_CALLBACK is ignored.
374 * We have to cope with that in our callback function.
375 */
376 RelTime = ktime_add_ns(ktime_set(0, 0), ullTimeNs_p);
377 hrtimer_start(&pTimerInfo->m_Timer, RelTime, HRTIMER_MODE_REL);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800378
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800379 Exit:
380 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800381
382}
383
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800384//---------------------------------------------------------------------------
385//
386// Function: EplTimerHighReskDeleteTimer()
387//
388// Description: deletes the timer with the specified handle. Afterward the
389// handle is set to zero.
390//
391// Parameters: pTimerHdl_p = pointer to timer handle
392//
393// Return: tEplKernel = error code
394//
395// State: not tested
396//
397//---------------------------------------------------------------------------
398
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800399tEplKernel PUBLIC EplTimerHighReskDeleteTimer(tEplTimerHdl * pTimerHdl_p)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800400{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800401 tEplKernel Ret = kEplSuccessful;
402 unsigned int uiIndex;
403 tEplTimerHighReskTimerInfo *pTimerInfo;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800404
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800405 // check pointer to handle
406 if (pTimerHdl_p == NULL) {
407 Ret = kEplTimerInvalidHandle;
408 goto Exit;
409 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800410
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800411 if (*pTimerHdl_p == 0) { // no timer created yet
412 goto Exit;
413 } else {
414 uiIndex = HDL_TO_IDX(*pTimerHdl_p);
415 if (uiIndex >= TIMER_COUNT) { // invalid handle
416 Ret = kEplTimerInvalidHandle;
417 goto Exit;
418 }
419 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
420 if (pTimerInfo->m_EventArg.m_TimerHdl != *pTimerHdl_p) { // invalid handle
421 goto Exit;
422 }
423 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800424
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800425 *pTimerHdl_p = 0;
426 pTimerInfo->m_EventArg.m_TimerHdl = 0;
427 pTimerInfo->m_pfnCallback = NULL;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800428
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800429 /*
430 * Three return cases of hrtimer_try_to_cancel have to be tracked:
431 * 1 - timer has been removed
432 * 0 - timer was not active
433 * We need not do anything. hrtimer timers just consist of
434 * a hrtimer struct, which we might enqueue in the hrtimers
435 * event list by calling hrtimer_start().
436 * If a timer is not enqueued, it is not present in hrtimers.
437 * -1 - callback function is running
438 * In this case we have to ensure that the timer is not
439 * continuously restarted. This has been done by clearing
440 * its handle.
441 */
442 hrtimer_try_to_cancel(&pTimerInfo->m_Timer);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800443
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800444 Exit:
445 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800446
447}
448
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800449//---------------------------------------------------------------------------
450//
451// Function: EplTimerHighReskCallback()
452//
453// Description: Callback function commonly used for all timers.
454//
455// Parameters: pTimer_p = pointer to hrtimer
456//
457// Return:
458//
459// State: not tested
460//
461//---------------------------------------------------------------------------
462
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800463enum hrtimer_restart EplTimerHighReskCallback(struct hrtimer *pTimer_p)
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800464{
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800465 unsigned int uiIndex;
466 tEplTimerHighReskTimerInfo *pTimerInfo;
467 tEplTimerHdl OrgTimerHdl;
468 enum hrtimer_restart Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800469
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800470 BENCHMARK_MOD_24_SET(4);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800471
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800472 Ret = HRTIMER_NORESTART;
473 pTimerInfo =
474 container_of(pTimer_p, tEplTimerHighReskTimerInfo, m_Timer);
475 uiIndex = HDL_TO_IDX(pTimerInfo->m_EventArg.m_TimerHdl);
476 if (uiIndex >= TIMER_COUNT) { // invalid handle
477 goto Exit;
478 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800479
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800480 /*
481 * We store the timer handle before calling the callback function
482 * as the timer can be modified inside it.
483 */
484 OrgTimerHdl = pTimerInfo->m_EventArg.m_TimerHdl;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800485
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800486 if (pTimerInfo->m_pfnCallback != NULL) {
487 pTimerInfo->m_pfnCallback(&pTimerInfo->m_EventArg);
488 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800489
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800490 if (pTimerInfo->m_fContinuously) {
491 ktime_t Interval;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800492#ifdef PROVE_OVERRUN
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800493 ktime_t Now;
494 unsigned long Overruns;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800495#endif
496
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800497 if (OrgTimerHdl != pTimerInfo->m_EventArg.m_TimerHdl) {
498 /* modified timer has already been restarted */
499 goto Exit;
500 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800501#ifdef PROVE_OVERRUN
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800502 Now = ktime_get();
503 Interval =
504 ktime_add_ns(ktime_set(0, 0), pTimerInfo->m_ullPeriod);
505 Overruns = hrtimer_forward(pTimer_p, Now, Interval);
506 if (Overruns > 1) {
507 printk
508 ("EplTimerHighResk: Continuous timer (handle 0x%lX) had to skip %lu interval(s)!\n",
509 pTimerInfo->m_EventArg.m_TimerHdl, Overruns - 1);
510 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800511#else
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800512 pTimer_p->expires = ktime_add_ns(pTimer_p->expires,
513 pTimerInfo->m_ullPeriod);
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800514#endif
515
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800516 Ret = HRTIMER_RESTART;
517 }
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800518
Greg Kroah-Hartman833dfbe2008-12-19 17:11:52 -0800519 Exit:
520 BENCHMARK_MOD_24_RESET(4);
521 return Ret;
Daniel Krueger9d7164c2008-12-19 11:41:57 -0800522}