Linux-2.6.12-rc2
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / net / sk98lin / sktimer.c
1 /******************************************************************************
2 *
3 * Name: sktimer.c
4 * Project: Gigabit Ethernet Adapters, Event Scheduler Module
5 * Version: $Revision: 1.14 $
6 * Date: $Date: 2003/09/16 13:46:51 $
7 * Purpose: High level timer functions.
8 *
9 ******************************************************************************/
10
11 /******************************************************************************
12 *
13 * (C)Copyright 1998-2002 SysKonnect GmbH.
14 * (C)Copyright 2002-2003 Marvell.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * The information in this file is provided "AS IS" without warranty.
22 *
23 ******************************************************************************/
24
25
26 /*
27 * Event queue and dispatcher
28 */
29 #if (defined(DEBUG) || ((!defined(LINT)) && (!defined(SK_SLIM))))
30 static const char SysKonnectFileId[] =
31 "@(#) $Id: sktimer.c,v 1.14 2003/09/16 13:46:51 rschmidt Exp $ (C) Marvell.";
32 #endif
33
34 #include "h/skdrv1st.h" /* Driver Specific Definitions */
35 #include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */
36
37 #ifdef __C2MAN__
38 /*
39 Event queue management.
40
41 General Description:
42
43 */
44 intro()
45 {}
46 #endif
47
48
49 /* Forward declaration */
50 static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart);
51
52
53 /*
54 * Inits the software timer
55 *
56 * needs to be called during Init level 1.
57 */
58 void SkTimerInit(
59 SK_AC *pAC, /* Adapters context */
60 SK_IOC Ioc, /* IoContext */
61 int Level) /* Init Level */
62 {
63 switch (Level) {
64 case SK_INIT_DATA:
65 pAC->Tim.StQueue = NULL;
66 break;
67 case SK_INIT_IO:
68 SkHwtInit(pAC, Ioc);
69 SkTimerDone(pAC, Ioc);
70 break;
71 default:
72 break;
73 }
74 }
75
76 /*
77 * Stops a high level timer
78 * - If a timer is not in the queue the function returns normally, too.
79 */
80 void SkTimerStop(
81 SK_AC *pAC, /* Adapters context */
82 SK_IOC Ioc, /* IoContext */
83 SK_TIMER *pTimer) /* Timer Pointer to be started */
84 {
85 SK_TIMER **ppTimPrev;
86 SK_TIMER *pTm;
87
88 /*
89 * remove timer from queue
90 */
91 pTimer->TmActive = SK_FALSE;
92
93 if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) {
94 SkHwtStop(pAC, Ioc);
95 }
96
97 for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev);
98 ppTimPrev = &pTm->TmNext ) {
99
100 if (pTm == pTimer) {
101 /*
102 * Timer found in queue
103 * - dequeue it and
104 * - correct delta of the next timer
105 */
106 *ppTimPrev = pTm->TmNext;
107
108 if (pTm->TmNext) {
109 /* correct delta of next timer in queue */
110 pTm->TmNext->TmDelta += pTm->TmDelta;
111 }
112 return;
113 }
114 }
115 }
116
117 /*
118 * Start a high level software timer
119 */
120 void SkTimerStart(
121 SK_AC *pAC, /* Adapters context */
122 SK_IOC Ioc, /* IoContext */
123 SK_TIMER *pTimer, /* Timer Pointer to be started */
124 SK_U32 Time, /* Time value */
125 SK_U32 Class, /* Event Class for this timer */
126 SK_U32 Event, /* Event Value for this timer */
127 SK_EVPARA Para) /* Event Parameter for this timer */
128 {
129 SK_TIMER **ppTimPrev;
130 SK_TIMER *pTm;
131 SK_U32 Delta;
132
133 Time /= 16; /* input is uS, clock ticks are 16uS */
134
135 if (!Time)
136 Time = 1;
137
138 SkTimerStop(pAC, Ioc, pTimer);
139
140 pTimer->TmClass = Class;
141 pTimer->TmEvent = Event;
142 pTimer->TmPara = Para;
143 pTimer->TmActive = SK_TRUE;
144
145 if (!pAC->Tim.StQueue) {
146 /* First Timer to be started */
147 pAC->Tim.StQueue = pTimer;
148 pTimer->TmNext = NULL;
149 pTimer->TmDelta = Time;
150
151 SkHwtStart(pAC, Ioc, Time);
152
153 return;
154 }
155
156 /*
157 * timer correction
158 */
159 timer_done(pAC, Ioc, 0);
160
161 /*
162 * find position in queue
163 */
164 Delta = 0;
165 for (ppTimPrev = &pAC->Tim.StQueue; (pTm = *ppTimPrev);
166 ppTimPrev = &pTm->TmNext ) {
167
168 if (Delta + pTm->TmDelta > Time) {
169 /* Position found */
170 /* Here the timer needs to be inserted. */
171 break;
172 }
173 Delta += pTm->TmDelta;
174 }
175
176 /* insert in queue */
177 *ppTimPrev = pTimer;
178 pTimer->TmNext = pTm;
179 pTimer->TmDelta = Time - Delta;
180
181 if (pTm) {
182 /* There is a next timer
183 * -> correct its Delta value.
184 */
185 pTm->TmDelta -= pTimer->TmDelta;
186 }
187
188 /* restart with first */
189 SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta);
190 }
191
192
193 void SkTimerDone(
194 SK_AC *pAC, /* Adapters context */
195 SK_IOC Ioc) /* IoContext */
196 {
197 timer_done(pAC, Ioc, 1);
198 }
199
200
201 static void timer_done(
202 SK_AC *pAC, /* Adapters context */
203 SK_IOC Ioc, /* IoContext */
204 int Restart) /* Do we need to restart the Hardware timer ? */
205 {
206 SK_U32 Delta;
207 SK_TIMER *pTm;
208 SK_TIMER *pTComp; /* Timer completed now now */
209 SK_TIMER **ppLast; /* Next field of Last timer to be deq */
210 int Done = 0;
211
212 Delta = SkHwtRead(pAC, Ioc);
213
214 ppLast = &pAC->Tim.StQueue;
215 pTm = pAC->Tim.StQueue;
216 while (pTm && !Done) {
217 if (Delta >= pTm->TmDelta) {
218 /* Timer ran out */
219 pTm->TmActive = SK_FALSE;
220 Delta -= pTm->TmDelta;
221 ppLast = &pTm->TmNext;
222 pTm = pTm->TmNext;
223 }
224 else {
225 /* We found the first timer that did not run out */
226 pTm->TmDelta -= Delta;
227 Delta = 0;
228 Done = 1;
229 }
230 }
231 *ppLast = NULL;
232 /*
233 * pTm points to the first Timer that did not run out.
234 * StQueue points to the first Timer that run out.
235 */
236
237 for ( pTComp = pAC->Tim.StQueue; pTComp; pTComp = pTComp->TmNext) {
238 SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, pTComp->TmPara);
239 }
240
241 /* Set head of timer queue to the first timer that did not run out */
242 pAC->Tim.StQueue = pTm;
243
244 if (Restart && pAC->Tim.StQueue) {
245 /* Restart HW timer */
246 SkHwtStart(pAC, Ioc, pAC->Tim.StQueue->TmDelta);
247 }
248 }
249
250 /* End of file */