Staging: epl: remove PUBLIC definition
[linux-2.6/mini2440.git] / drivers / staging / epl / TimerHighReskX86.c
blob11ae8192323d00efbf0846426ebe8d3609a9939e
1 /****************************************************************************
3 (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4 www.systec-electronic.com
6 Project: openPOWERLINK
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.
14 License:
16 Redistribution and use in source and binary forms, with or without
17 modification, are permitted provided that the following conditions
18 are met:
20 1. Redistributions of source code must retain the above copyright
21 notice, this list of conditions and the following disclaimer.
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.
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.
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.
45 Severability Clause:
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.
54 -------------------------------------------------------------------------
56 $RCSfile: TimerHighReskX86.c,v $
58 $Author: D.Krueger $
60 $Revision: 1.4 $ $Date: 2008/04/17 21:38:01 $
62 $State: Exp $
64 Build Environment:
65 GNU
67 -------------------------------------------------------------------------
69 Revision History:
71 ****************************************************************************/
73 #include "EplInc.h"
74 #include "kernel/EplTimerHighResk.h"
75 #include "Benchmark.h"
77 //#include <linux/config.h>
78 #include <linux/module.h>
79 #include <linux/kernel.h>
80 #include <linux/hrtimer.h>
82 /***************************************************************************/
83 /* */
84 /* */
85 /* G L O B A L D E F I N I T I O N S */
86 /* */
87 /* */
88 /***************************************************************************/
90 //---------------------------------------------------------------------------
91 // const defines
92 //---------------------------------------------------------------------------
94 #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 */
98 #define PROVE_OVERRUN
100 #ifndef CONFIG_HIGH_RES_TIMERS
101 #error "Kernel symbol CONFIG_HIGH_RES_TIMERS is required."
102 #endif
104 // TracePoint support for realtime-debugging
105 #ifdef _DBG_TRACE_POINTS_
106 void TgtDbgSignalTracePoint(BYTE bTracePointNumber_p);
107 void TgtDbgPostTraceValue(DWORD dwTraceValue_p);
108 #define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
109 #define TGT_DBG_POST_TRACE_VALUE(v) TgtDbgPostTraceValue(v)
110 #else
111 #define TGT_DBG_SIGNAL_TRACE_POINT(p)
112 #define TGT_DBG_POST_TRACE_VALUE(v)
113 #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)
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))
125 //---------------------------------------------------------------------------
126 // modul global types
127 //---------------------------------------------------------------------------
129 typedef struct {
130 tEplTimerEventArg m_EventArg;
131 tEplTimerkCallback m_pfnCallback;
132 struct hrtimer m_Timer;
133 BOOL m_fContinuously;
134 unsigned long long m_ullPeriod;
136 } tEplTimerHighReskTimerInfo;
138 typedef struct {
139 tEplTimerHighReskTimerInfo m_aTimerInfo[TIMER_COUNT];
141 } tEplTimerHighReskInstance;
143 //---------------------------------------------------------------------------
144 // local vars
145 //---------------------------------------------------------------------------
147 static tEplTimerHighReskInstance EplTimerHighReskInstance_l;
149 //---------------------------------------------------------------------------
150 // local function prototypes
151 //---------------------------------------------------------------------------
153 enum hrtimer_restart EplTimerHighReskCallback(struct hrtimer *pTimer_p);
155 //=========================================================================//
156 // //
157 // P U B L I C F U N C T I O N S //
158 // //
159 //=========================================================================//
161 //---------------------------------------------------------------------------
163 // Function: EplTimerHighReskInit()
165 // Description: initializes the high resolution timer module.
167 // Parameters: void
169 // Return: tEplKernel = error code
171 // State: not tested
173 //---------------------------------------------------------------------------
175 tEplKernel EplTimerHighReskInit(void)
177 tEplKernel Ret;
179 Ret = EplTimerHighReskAddInstance();
181 return Ret;
185 //---------------------------------------------------------------------------
187 // Function: EplTimerHighReskAddInstance()
189 // Description: initializes the high resolution timer module.
191 // Parameters: void
193 // Return: tEplKernel = error code
195 // State: not tested
197 //---------------------------------------------------------------------------
199 tEplKernel EplTimerHighReskAddInstance(void)
201 tEplKernel Ret;
202 unsigned int uiIndex;
204 Ret = kEplSuccessful;
206 EPL_MEMSET(&EplTimerHighReskInstance_l, 0,
207 sizeof(EplTimerHighReskInstance_l));
209 #ifndef CONFIG_HIGH_RES_TIMERS
210 printk
211 ("EplTimerHighResk: Kernel symbol CONFIG_HIGH_RES_TIMERS is required.\n");
212 Ret = kEplNoResource;
213 return Ret;
214 #endif
217 * Initialize hrtimer structures for all usable timers.
219 for (uiIndex = 0; uiIndex < TIMER_COUNT; uiIndex++) {
220 tEplTimerHighReskTimerInfo *pTimerInfo;
221 struct hrtimer *pTimer;
223 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
224 pTimer = &pTimerInfo->m_Timer;
225 hrtimer_init(pTimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
227 pTimer->function = EplTimerHighReskCallback;
230 return Ret;
233 //---------------------------------------------------------------------------
235 // Function: EplTimerHighReskDelInstance()
237 // Description: shuts down the high resolution timer module.
239 // Parameters: void
241 // Return: tEplKernel = error code
243 // State: not tested
245 //---------------------------------------------------------------------------
247 tEplKernel EplTimerHighReskDelInstance(void)
249 tEplTimerHighReskTimerInfo *pTimerInfo;
250 tEplKernel Ret;
251 unsigned int uiIndex;
253 Ret = kEplSuccessful;
255 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;
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.
264 hrtimer_cancel(&pTimerInfo->m_Timer);
267 return Ret;
271 //---------------------------------------------------------------------------
273 // Function: EplTimerHighReskModifyTimerNs()
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.
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.
295 // Return: tEplKernel = error code
297 // State: not tested
299 //---------------------------------------------------------------------------
301 tEplKernel EplTimerHighReskModifyTimerNs(tEplTimerHdl *pTimerHdl_p,
302 unsigned long long ullTimeNs_p,
303 tEplTimerkCallback pfnCallback_p,
304 unsigned long ulArgument_p,
305 BOOL fContinuously_p)
307 tEplKernel Ret;
308 unsigned int uiIndex;
309 tEplTimerHighReskTimerInfo *pTimerInfo;
310 ktime_t RelTime;
312 Ret = kEplSuccessful;
314 // check pointer to handle
315 if (pTimerHdl_p == NULL) {
316 Ret = kEplTimerInvalidHandle;
317 goto Exit;
320 if (*pTimerHdl_p == 0) { // no timer created yet
322 // search free timer info structure
323 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[0];
324 for (uiIndex = 0; uiIndex < TIMER_COUNT;
325 uiIndex++, pTimerInfo++) {
326 if (pTimerInfo->m_EventArg.m_TimerHdl == 0) { // free structure found
327 break;
330 if (uiIndex >= TIMER_COUNT) { // no free structure found
331 Ret = kEplTimerNoTimerCreated;
332 goto Exit;
335 pTimerInfo->m_EventArg.m_TimerHdl = HDL_INIT(uiIndex);
336 } else {
337 uiIndex = HDL_TO_IDX(*pTimerHdl_p);
338 if (uiIndex >= TIMER_COUNT) { // invalid handle
339 Ret = kEplTimerInvalidHandle;
340 goto Exit;
343 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
347 * increment timer handle
348 * (if timer expires right after this statement, the user
349 * would detect an unknown timer handle and discard it)
351 pTimerInfo->m_EventArg.m_TimerHdl =
352 HDL_INC(pTimerInfo->m_EventArg.m_TimerHdl);
353 *pTimerHdl_p = pTimerInfo->m_EventArg.m_TimerHdl;
355 // reject too small time values
356 if ((fContinuously_p && (ullTimeNs_p < TIMER_MIN_VAL_CYCLE))
357 || (!fContinuously_p && (ullTimeNs_p < TIMER_MIN_VAL_SINGLE))) {
358 Ret = kEplTimerNoTimerCreated;
359 goto Exit;
362 pTimerInfo->m_EventArg.m_ulArg = ulArgument_p;
363 pTimerInfo->m_pfnCallback = pfnCallback_p;
364 pTimerInfo->m_fContinuously = fContinuously_p;
365 pTimerInfo->m_ullPeriod = ullTimeNs_p;
368 * HRTIMER_MODE_REL does not influence general handling of this timer.
369 * It only sets relative mode for this start operation.
370 * -> Expire time is calculated by: Now + RelTime
371 * hrtimer_start also skips pending timer events.
372 * The state HRTIMER_STATE_CALLBACK is ignored.
373 * We have to cope with that in our callback function.
375 RelTime = ktime_add_ns(ktime_set(0, 0), ullTimeNs_p);
376 hrtimer_start(&pTimerInfo->m_Timer, RelTime, HRTIMER_MODE_REL);
378 Exit:
379 return Ret;
383 //---------------------------------------------------------------------------
385 // Function: EplTimerHighReskDeleteTimer()
387 // Description: deletes the timer with the specified handle. Afterward the
388 // handle is set to zero.
390 // Parameters: pTimerHdl_p = pointer to timer handle
392 // Return: tEplKernel = error code
394 // State: not tested
396 //---------------------------------------------------------------------------
398 tEplKernel EplTimerHighReskDeleteTimer(tEplTimerHdl *pTimerHdl_p)
400 tEplKernel Ret = kEplSuccessful;
401 unsigned int uiIndex;
402 tEplTimerHighReskTimerInfo *pTimerInfo;
404 // check pointer to handle
405 if (pTimerHdl_p == NULL) {
406 Ret = kEplTimerInvalidHandle;
407 goto Exit;
410 if (*pTimerHdl_p == 0) { // no timer created yet
411 goto Exit;
412 } else {
413 uiIndex = HDL_TO_IDX(*pTimerHdl_p);
414 if (uiIndex >= TIMER_COUNT) { // invalid handle
415 Ret = kEplTimerInvalidHandle;
416 goto Exit;
418 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
419 if (pTimerInfo->m_EventArg.m_TimerHdl != *pTimerHdl_p) { // invalid handle
420 goto Exit;
424 *pTimerHdl_p = 0;
425 pTimerInfo->m_EventArg.m_TimerHdl = 0;
426 pTimerInfo->m_pfnCallback = NULL;
429 * Three return cases of hrtimer_try_to_cancel have to be tracked:
430 * 1 - timer has been removed
431 * 0 - timer was not active
432 * We need not do anything. hrtimer timers just consist of
433 * a hrtimer struct, which we might enqueue in the hrtimers
434 * event list by calling hrtimer_start().
435 * If a timer is not enqueued, it is not present in hrtimers.
436 * -1 - callback function is running
437 * In this case we have to ensure that the timer is not
438 * continuously restarted. This has been done by clearing
439 * its handle.
441 hrtimer_try_to_cancel(&pTimerInfo->m_Timer);
443 Exit:
444 return Ret;
448 //---------------------------------------------------------------------------
450 // Function: EplTimerHighReskCallback()
452 // Description: Callback function commonly used for all timers.
454 // Parameters: pTimer_p = pointer to hrtimer
456 // Return:
458 // State: not tested
460 //---------------------------------------------------------------------------
462 enum hrtimer_restart EplTimerHighReskCallback(struct hrtimer *pTimer_p)
464 unsigned int uiIndex;
465 tEplTimerHighReskTimerInfo *pTimerInfo;
466 tEplTimerHdl OrgTimerHdl;
467 enum hrtimer_restart Ret;
469 BENCHMARK_MOD_24_SET(4);
471 Ret = HRTIMER_NORESTART;
472 pTimerInfo =
473 container_of(pTimer_p, tEplTimerHighReskTimerInfo, m_Timer);
474 uiIndex = HDL_TO_IDX(pTimerInfo->m_EventArg.m_TimerHdl);
475 if (uiIndex >= TIMER_COUNT) { // invalid handle
476 goto Exit;
480 * We store the timer handle before calling the callback function
481 * as the timer can be modified inside it.
483 OrgTimerHdl = pTimerInfo->m_EventArg.m_TimerHdl;
485 if (pTimerInfo->m_pfnCallback != NULL) {
486 pTimerInfo->m_pfnCallback(&pTimerInfo->m_EventArg);
489 if (pTimerInfo->m_fContinuously) {
490 ktime_t Interval;
491 #ifdef PROVE_OVERRUN
492 ktime_t Now;
493 unsigned long Overruns;
494 #endif
496 if (OrgTimerHdl != pTimerInfo->m_EventArg.m_TimerHdl) {
497 /* modified timer has already been restarted */
498 goto Exit;
500 #ifdef PROVE_OVERRUN
501 Now = ktime_get();
502 Interval =
503 ktime_add_ns(ktime_set(0, 0), pTimerInfo->m_ullPeriod);
504 Overruns = hrtimer_forward(pTimer_p, Now, Interval);
505 if (Overruns > 1) {
506 printk
507 ("EplTimerHighResk: Continuous timer (handle 0x%lX) had to skip %lu interval(s)!\n",
508 pTimerInfo->m_EventArg.m_TimerHdl, Overruns - 1);
510 #else
511 pTimer_p->expires = ktime_add_ns(pTimer_p->expires,
512 pTimerInfo->m_ullPeriod);
513 #endif
515 Ret = HRTIMER_RESTART;
518 Exit:
519 BENCHMARK_MOD_24_RESET(4);
520 return Ret;