wl1251: move module probe methods into spi.c
[linux-2.6/btrfs-unstable.git] / drivers / staging / epl / TimerHighReskX86.c
blobd6897de4f140db96ded303aaa5fea7b73e626af7
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 // TracePoint support for realtime-debugging
101 #ifdef _DBG_TRACE_POINTS_
102 void TgtDbgSignalTracePoint(u8 bTracePointNumber_p);
103 void TgtDbgPostTraceValue(u32 dwTraceValue_p);
104 #define TGT_DBG_SIGNAL_TRACE_POINT(p) TgtDbgSignalTracePoint(p)
105 #define TGT_DBG_POST_TRACE_VALUE(v) TgtDbgPostTraceValue(v)
106 #else
107 #define TGT_DBG_SIGNAL_TRACE_POINT(p)
108 #define TGT_DBG_POST_TRACE_VALUE(v)
109 #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)
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))
121 //---------------------------------------------------------------------------
122 // modul global types
123 //---------------------------------------------------------------------------
125 typedef struct {
126 tEplTimerEventArg m_EventArg;
127 tEplTimerkCallback m_pfnCallback;
128 struct hrtimer m_Timer;
129 BOOL m_fContinuously;
130 unsigned long long m_ullPeriod;
132 } tEplTimerHighReskTimerInfo;
134 typedef struct {
135 tEplTimerHighReskTimerInfo m_aTimerInfo[TIMER_COUNT];
137 } tEplTimerHighReskInstance;
139 //---------------------------------------------------------------------------
140 // local vars
141 //---------------------------------------------------------------------------
143 static tEplTimerHighReskInstance EplTimerHighReskInstance_l;
145 //---------------------------------------------------------------------------
146 // local function prototypes
147 //---------------------------------------------------------------------------
149 enum hrtimer_restart EplTimerHighReskCallback(struct hrtimer *pTimer_p);
151 //=========================================================================//
152 // //
153 // P U B L I C F U N C T I O N S //
154 // //
155 //=========================================================================//
157 //---------------------------------------------------------------------------
159 // Function: EplTimerHighReskInit()
161 // Description: initializes the high resolution timer module.
163 // Parameters: void
165 // Return: tEplKernel = error code
167 // State: not tested
169 //---------------------------------------------------------------------------
171 tEplKernel EplTimerHighReskInit(void)
173 tEplKernel Ret;
175 Ret = EplTimerHighReskAddInstance();
177 return Ret;
181 //---------------------------------------------------------------------------
183 // Function: EplTimerHighReskAddInstance()
185 // Description: initializes the high resolution timer module.
187 // Parameters: void
189 // Return: tEplKernel = error code
191 // State: not tested
193 //---------------------------------------------------------------------------
195 tEplKernel EplTimerHighReskAddInstance(void)
197 tEplKernel Ret;
198 unsigned int uiIndex;
200 Ret = kEplSuccessful;
202 EPL_MEMSET(&EplTimerHighReskInstance_l, 0,
203 sizeof(EplTimerHighReskInstance_l));
206 * Initialize hrtimer structures for all usable timers.
208 for (uiIndex = 0; uiIndex < TIMER_COUNT; uiIndex++) {
209 tEplTimerHighReskTimerInfo *pTimerInfo;
210 struct hrtimer *pTimer;
212 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
213 pTimer = &pTimerInfo->m_Timer;
214 hrtimer_init(pTimer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
216 pTimer->function = EplTimerHighReskCallback;
219 return Ret;
222 //---------------------------------------------------------------------------
224 // Function: EplTimerHighReskDelInstance()
226 // Description: shuts down the high resolution timer module.
228 // Parameters: void
230 // Return: tEplKernel = error code
232 // State: not tested
234 //---------------------------------------------------------------------------
236 tEplKernel EplTimerHighReskDelInstance(void)
238 tEplTimerHighReskTimerInfo *pTimerInfo;
239 tEplKernel Ret;
240 unsigned int uiIndex;
242 Ret = kEplSuccessful;
244 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;
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.
253 hrtimer_cancel(&pTimerInfo->m_Timer);
256 return Ret;
260 //---------------------------------------------------------------------------
262 // Function: EplTimerHighReskModifyTimerNs()
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.
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.
284 // Return: tEplKernel = error code
286 // State: not tested
288 //---------------------------------------------------------------------------
290 tEplKernel EplTimerHighReskModifyTimerNs(tEplTimerHdl *pTimerHdl_p,
291 unsigned long long ullTimeNs_p,
292 tEplTimerkCallback pfnCallback_p,
293 unsigned long ulArgument_p,
294 BOOL fContinuously_p)
296 tEplKernel Ret;
297 unsigned int uiIndex;
298 tEplTimerHighReskTimerInfo *pTimerInfo;
299 ktime_t RelTime;
301 Ret = kEplSuccessful;
303 // check pointer to handle
304 if (pTimerHdl_p == NULL) {
305 Ret = kEplTimerInvalidHandle;
306 goto Exit;
309 if (*pTimerHdl_p == 0) { // no timer created yet
311 // 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;
319 if (uiIndex >= TIMER_COUNT) { // no free structure found
320 Ret = kEplTimerNoTimerCreated;
321 goto Exit;
324 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;
332 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
336 * increment timer handle
337 * (if timer expires right after this statement, the user
338 * would detect an unknown timer handle and discard it)
340 pTimerInfo->m_EventArg.m_TimerHdl =
341 HDL_INC(pTimerInfo->m_EventArg.m_TimerHdl);
342 *pTimerHdl_p = pTimerInfo->m_EventArg.m_TimerHdl;
344 // 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;
351 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;
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.
364 RelTime = ktime_add_ns(ktime_set(0, 0), ullTimeNs_p);
365 hrtimer_start(&pTimerInfo->m_Timer, RelTime, HRTIMER_MODE_REL);
367 Exit:
368 return Ret;
372 //---------------------------------------------------------------------------
374 // Function: EplTimerHighReskDeleteTimer()
376 // Description: deletes the timer with the specified handle. Afterward the
377 // handle is set to zero.
379 // Parameters: pTimerHdl_p = pointer to timer handle
381 // Return: tEplKernel = error code
383 // State: not tested
385 //---------------------------------------------------------------------------
387 tEplKernel EplTimerHighReskDeleteTimer(tEplTimerHdl *pTimerHdl_p)
389 tEplKernel Ret = kEplSuccessful;
390 unsigned int uiIndex;
391 tEplTimerHighReskTimerInfo *pTimerInfo;
393 // check pointer to handle
394 if (pTimerHdl_p == NULL) {
395 Ret = kEplTimerInvalidHandle;
396 goto Exit;
399 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;
407 pTimerInfo = &EplTimerHighReskInstance_l.m_aTimerInfo[uiIndex];
408 if (pTimerInfo->m_EventArg.m_TimerHdl != *pTimerHdl_p) { // invalid handle
409 goto Exit;
413 *pTimerHdl_p = 0;
414 pTimerInfo->m_EventArg.m_TimerHdl = 0;
415 pTimerInfo->m_pfnCallback = NULL;
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.
430 hrtimer_try_to_cancel(&pTimerInfo->m_Timer);
432 Exit:
433 return Ret;
437 //---------------------------------------------------------------------------
439 // Function: EplTimerHighReskCallback()
441 // Description: Callback function commonly used for all timers.
443 // Parameters: pTimer_p = pointer to hrtimer
445 // Return:
447 // State: not tested
449 //---------------------------------------------------------------------------
451 enum hrtimer_restart EplTimerHighReskCallback(struct hrtimer *pTimer_p)
453 unsigned int uiIndex;
454 tEplTimerHighReskTimerInfo *pTimerInfo;
455 tEplTimerHdl OrgTimerHdl;
456 enum hrtimer_restart Ret;
458 BENCHMARK_MOD_24_SET(4);
460 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;
469 * We store the timer handle before calling the callback function
470 * as the timer can be modified inside it.
472 OrgTimerHdl = pTimerInfo->m_EventArg.m_TimerHdl;
474 if (pTimerInfo->m_pfnCallback != NULL) {
475 pTimerInfo->m_pfnCallback(&pTimerInfo->m_EventArg);
478 if (pTimerInfo->m_fContinuously) {
479 ktime_t Interval;
480 #ifdef PROVE_OVERRUN
481 ktime_t Now;
482 unsigned long Overruns;
483 #endif
485 if (OrgTimerHdl != pTimerInfo->m_EventArg.m_TimerHdl) {
486 /* modified timer has already been restarted */
487 goto Exit;
489 #ifdef PROVE_OVERRUN
490 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);
499 #else
500 pTimer_p->expires = ktime_add_ns(pTimer_p->expires,
501 pTimerInfo->m_ullPeriod);
502 #endif
504 Ret = HRTIMER_RESTART;
507 Exit:
508 BENCHMARK_MOD_24_RESET(4);
509 return Ret;