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