File: /usr/src/linux/drivers/net/sk98lin/sktimer.c
1 /******************************************************************************
2 *
3 * Name: sktimer.c
4 * Project: PCI Gigabit Ethernet Adapter
5 * Version: $Revision: 1.11 $
6 * Date: $Date: 1998/12/17 13:24:13 $
7 * Purpose: High level timer functions.
8 *
9 ******************************************************************************/
10
11 /******************************************************************************
12 *
13 * (C)Copyright 1989-1998 SysKonnect,
14 * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
15 * All Rights Reserved
16 *
17 * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF SYSKONNECT
18 * The copyright notice above does not evidence any
19 * actual or intended publication of such source code.
20 *
21 * This Module contains Proprietary Information of SysKonnect
22 * and should be treated as Confidential.
23 *
24 * The information in this file is provided for the exclusive use of
25 * the licensees of SysKonnect.
26 * Such users have the right to use, modify, and incorporate this code
27 * into products for purposes authorized by the license agreement
28 * provided they include this notice and the associated copyright notice
29 * with any such product.
30 * The information in this file is provided "AS IS" without warranty.
31 *
32 ******************************************************************************/
33
34 /******************************************************************************
35 *
36 * History:
37 *
38 * $Log: sktimer.c,v $
39 * Revision 1.11 1998/12/17 13:24:13 gklug
40 * fix: restart problem: do NOT destroy timer queue if init 1 is done
41 *
42 * Revision 1.10 1998/10/15 15:11:36 gklug
43 * fix: ID_sccs to SysKonnectFileId
44 *
45 * Revision 1.9 1998/09/15 15:15:04 cgoos
46 * Changed TRUE/FALSE to SK_TRUE/SK_FALSE
47 *
48 * Revision 1.8 1998/09/08 08:47:55 gklug
49 * add: init level handling
50 *
51 * Revision 1.7 1998/08/19 09:50:53 gklug
52 * fix: remove struct keyword from c-code (see CCC) add typedefs
53 *
54 * Revision 1.6 1998/08/17 13:43:13 gklug
55 * chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR
56 *
57 * Revision 1.5 1998/08/14 07:09:14 gklug
58 * fix: chg pAc -> pAC
59 *
60 * Revision 1.4 1998/08/07 12:53:46 gklug
61 * fix: first compiled version
62 *
63 * Revision 1.3 1998/08/07 09:31:53 gklug
64 * fix: delta spelling
65 *
66 * Revision 1.2 1998/08/07 09:31:02 gklug
67 * adapt functions to new c coding conventions
68 * rmv: "fast" handling
69 * chg: inserting of new timer in queue.
70 * chg: event queue generation when timer runs out
71 *
72 * Revision 1.1 1998/08/05 11:27:55 gklug
73 * first version: adapted from SMT
74 *
75 *
76 *
77 *
78 ******************************************************************************/
79
80
81 /*
82 Event queue and dispatcher
83 */
84 static const char SysKonnectFileId[] =
85 "$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.11 1998/12/17 13:24:13 gklug Exp $" ;
86
87 #include "h/skdrv1st.h" /* Driver Specific Definitions */
88 #include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */
89
90 #ifdef __C2MAN__
91 /*
92 Event queue management.
93
94 General Description:
95
96 */
97 intro()
98 {}
99 #endif
100
101
102 /* Forward declaration */
103 static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart);
104
105
106 /*
107 * Inits the software timer
108 *
109 * needs to be called during Init level 1.
110 */
111 void SkTimerInit(
112 SK_AC *pAC, /* Adapters context */
113 SK_IOC Ioc, /* IoContext */
114 int Level) /* Init Level */
115 {
116 switch (Level) {
117 case SK_INIT_DATA:
118 pAC->Tim.StQueue = 0 ;
119 break;
120 case SK_INIT_IO:
121 SkHwtInit(pAC,Ioc) ;
122 SkTimerDone(pAC, Ioc);
123 break;
124 default:
125 break;
126 }
127 }
128
129 /*
130 * Stops a high level timer
131 * - If a timer is not in the queue the function returns normally, too.
132 */
133 void SkTimerStop(
134 SK_AC *pAC, /* Adapters context */
135 SK_IOC Ioc, /* IoContext */
136 SK_TIMER *pTimer) /* Timer Pointer to be started */
137 {
138 SK_TIMER **ppTimPrev ;
139 SK_TIMER *pTm ;
140
141 /*
142 * remove timer from queue
143 */
144 pTimer->TmActive = SK_FALSE ;
145 if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) {
146 SkHwtStop(pAC,Ioc) ;
147 }
148 for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ;
149 ppTimPrev = &pTm->TmNext ) {
150 if (pTm == pTimer) {
151 /*
152 * Timer found in queue
153 * - dequeue it and
154 * - correct delta of the next timer
155 */
156 *ppTimPrev = pTm->TmNext ;
157
158 if (pTm->TmNext) {
159 /* correct delta of next timer in queue */
160 pTm->TmNext->TmDelta += pTm->TmDelta ;
161 }
162 return ;
163 }
164 }
165 }
166
167 /*
168 * Start a high level software timer
169 */
170 void SkTimerStart(
171 SK_AC *pAC, /* Adapters context */
172 SK_IOC Ioc, /* IoContext */
173 SK_TIMER *pTimer, /* Timer Pointer to be started */
174 SK_U32 Time, /* Time value */
175 SK_U32 Class, /* Event Class for this timer */
176 SK_U32 Event, /* Event Value for this timer */
177 SK_EVPARA Para) /* Event Parameter for this timer */
178 {
179 SK_TIMER **ppTimPrev ;
180 SK_TIMER *pTm ;
181 SK_U32 Delta ;
182
183 Time /= 16 ; /* input is uS, clock ticks are 16uS */
184 if (!Time)
185 Time = 1 ;
186
187 SkTimerStop(pAC,Ioc,pTimer) ;
188
189 pTimer->TmClass = Class ;
190 pTimer->TmEvent = Event ;
191 pTimer->TmPara = Para ;
192 pTimer->TmActive = SK_TRUE ;
193
194 if (!pAC->Tim.StQueue) {
195 /* First Timer to be started */
196 pAC->Tim.StQueue = pTimer ;
197 pTimer->TmNext = 0 ;
198 pTimer->TmDelta = Time ;
199 SkHwtStart(pAC,Ioc,Time) ;
200 return ;
201 }
202
203 /*
204 * timer correction
205 */
206 timer_done(pAC,Ioc,0) ;
207
208 /*
209 * find position in queue
210 */
211 Delta = 0 ;
212 for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ;
213 ppTimPrev = &pTm->TmNext ) {
214 if (Delta + pTm->TmDelta > Time) {
215 /* Position found */
216 /* Here the timer needs to be inserted. */
217 break ;
218 }
219 Delta += pTm->TmDelta ;
220 }
221
222 /* insert in queue */
223 *ppTimPrev = pTimer ;
224 pTimer->TmNext = pTm ;
225 pTimer->TmDelta = Time - Delta ;
226
227 if (pTm) {
228 /* There is a next timer
229 * -> correct its Delta value.
230 */
231 pTm->TmDelta -= pTimer->TmDelta ;
232 }
233
234 /*
235 * start new with first
236 */
237 SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ;
238 }
239
240
241 void SkTimerDone(
242 SK_AC *pAC, /* Adapters context */
243 SK_IOC Ioc) /* IoContext */
244 {
245 timer_done(pAC,Ioc,1) ;
246 }
247
248
249 static void timer_done(
250 SK_AC *pAC, /* Adapters context */
251 SK_IOC Ioc, /* IoContext */
252 int Restart) /* Do we need to restart the Hardware timer ? */
253 {
254 SK_U32 Delta ;
255 SK_TIMER *pTm ;
256 SK_TIMER *pTComp ; /* Timer completed now now */
257 SK_TIMER **ppLast ; /* Next field of Last timer to be deq */
258 int Done = 0 ;
259
260 Delta = SkHwtRead(pAC,Ioc) ;
261 ppLast = &pAC->Tim.StQueue ;
262 pTm = pAC->Tim.StQueue ;
263 while (pTm && !Done) {
264 if (Delta >= pTm->TmDelta) {
265 /* Timer ran out */
266 pTm->TmActive = SK_FALSE ;
267 Delta -= pTm->TmDelta ;
268 ppLast = &pTm->TmNext ;
269 pTm = pTm->TmNext ;
270 } else {
271 /* We found the first timer that did not run out */
272 pTm->TmDelta -= Delta ;
273 Delta = 0 ;
274 Done = 1 ;
275 }
276 }
277 *ppLast = 0 ;
278 /*
279 * pTm points to the first Timer that did not run out.
280 * StQueue points to the first Timer that run out.
281 */
282
283 for ( pTComp = pAC->Tim.StQueue ; pTComp ; pTComp = pTComp->TmNext) {
284 SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent,
285 pTComp->TmPara) ;
286 }
287
288 /* Set head of timer queue to the first timer that did not run out */
289 pAC->Tim.StQueue = pTm ;
290
291 if (Restart && pAC->Tim.StQueue) {
292 /* Restart HW timer */
293 SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ;
294 }
295 }
296
297 /* End of file */
298