]> git.kernelconcepts.de Git - karo-tx-uboot.git/blob - drivers/sk98lin/sktimer.c
* Patches by Xianghua Xiao, 15 Oct 2003:
[karo-tx-uboot.git] / drivers / sk98lin / sktimer.c
1 /******************************************************************************
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 #include <config.h>
76
77 #ifdef CONFIG_SK98
78
79 /*
80         Event queue and dispatcher
81 */
82 static const char SysKonnectFileId[] =
83         "$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.12 1999/11/22 13:38:51 cgoos Exp $" ;
84
85 #include "h/skdrv1st.h"         /* Driver Specific Definitions */
86 #include "h/skdrv2nd.h"         /* Adapter Control- and Driver specific Def. */
87
88 #ifdef __C2MAN__
89 /*
90         Event queue management.
91
92         General Description:
93
94  */
95 intro()
96 {}
97 #endif
98
99
100 /* Forward declaration */
101 static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart);
102
103
104 /*
105  * Inits the software timer
106  *
107  * needs to be called during Init level 1.
108  */
109 void    SkTimerInit(
110 SK_AC   *pAC,           /* Adapters context */
111 SK_IOC  Ioc,            /* IoContext */
112 int     Level)          /* Init Level */
113 {
114         switch (Level) {
115         case SK_INIT_DATA:
116                 pAC->Tim.StQueue = 0 ;
117                 break;
118         case SK_INIT_IO:
119                 SkHwtInit(pAC,Ioc) ;
120                 SkTimerDone(pAC, Ioc);
121                 break;
122         default:
123                 break;
124         }
125 }
126
127 /*
128  * Stops a high level timer
129  * - If a timer is not in the queue the function returns normally, too.
130  */
131 void    SkTimerStop(
132 SK_AC           *pAC,           /* Adapters context */
133 SK_IOC          Ioc,            /* IoContext */
134 SK_TIMER        *pTimer)        /* Timer Pointer to be started */
135 {
136         SK_TIMER        **ppTimPrev ;
137         SK_TIMER        *pTm ;
138
139         /*
140          * remove timer from queue
141          */
142         pTimer->TmActive = SK_FALSE ;
143         if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) {
144                 SkHwtStop(pAC,Ioc) ;
145         }
146         for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ;
147                 ppTimPrev = &pTm->TmNext ) {
148                 if (pTm == pTimer) {
149                         /*
150                          * Timer found in queue
151                          * - dequeue it and
152                          * - correct delta of the next timer
153                          */
154                         *ppTimPrev = pTm->TmNext ;
155
156                         if (pTm->TmNext) {
157                                 /* correct delta of next timer in queue */
158                                 pTm->TmNext->TmDelta += pTm->TmDelta ;
159                         }
160                         return ;
161                 }
162         }
163 }
164
165 /*
166  * Start a high level software timer
167  */
168 void    SkTimerStart(
169 SK_AC           *pAC,           /* Adapters context */
170 SK_IOC          Ioc,            /* IoContext */
171 SK_TIMER        *pTimer,        /* Timer Pointer to be started */
172 SK_U32          Time,           /* Time value */
173 SK_U32          Class,          /* Event Class for this timer */
174 SK_U32          Event,          /* Event Value for this timer */
175 SK_EVPARA       Para)           /* Event Parameter for this timer */
176 {
177         SK_TIMER        **ppTimPrev ;
178         SK_TIMER        *pTm ;
179         SK_U32          Delta ;
180
181         Time /= 16 ;            /* input is uS, clock ticks are 16uS */
182         if (!Time)
183                 Time = 1 ;
184
185         SkTimerStop(pAC,Ioc,pTimer) ;
186
187         pTimer->TmClass = Class ;
188         pTimer->TmEvent = Event ;
189         pTimer->TmPara = Para ;
190         pTimer->TmActive = SK_TRUE ;
191
192         if (!pAC->Tim.StQueue) {
193                 /* First Timer to be started */
194                 pAC->Tim.StQueue = pTimer ;
195                 pTimer->TmNext = 0 ;
196                 pTimer->TmDelta = Time ;
197                 SkHwtStart(pAC,Ioc,Time) ;
198                 return ;
199         }
200
201         /*
202          * timer correction
203          */
204         timer_done(pAC,Ioc,0) ;
205
206         /*
207          * find position in queue
208          */
209         Delta = 0 ;
210         for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ;
211                 ppTimPrev = &pTm->TmNext ) {
212                 if (Delta + pTm->TmDelta > Time) {
213                         /* Position found */
214                         /* Here the timer needs to be inserted. */
215                         break ;
216                 }
217                 Delta += pTm->TmDelta ;
218         }
219
220         /* insert in queue */
221         *ppTimPrev = pTimer ;
222         pTimer->TmNext = pTm ;
223         pTimer->TmDelta = Time - Delta ;
224
225         if (pTm) {
226                 /* There is a next timer
227                  * -> correct its Delta value.
228                  */
229                 pTm->TmDelta -= pTimer->TmDelta ;
230         }
231
232         /*
233          * start new with first
234          */
235         SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ;
236 }
237
238
239 void    SkTimerDone(
240 SK_AC   *pAC,           /* Adapters context */
241 SK_IOC  Ioc)            /* IoContext */
242 {
243         timer_done(pAC,Ioc,1) ;
244 }
245
246
247 static void     timer_done(
248 SK_AC   *pAC,           /* Adapters context */
249 SK_IOC  Ioc,            /* IoContext */
250 int     Restart)        /* Do we need to restart the Hardware timer ? */
251 {
252         SK_U32          Delta ;
253         SK_TIMER        *pTm ;
254         SK_TIMER        *pTComp ;       /* Timer completed now now */
255         SK_TIMER        **ppLast ;      /* Next field of Last timer to be deq */
256         int             Done = 0 ;
257
258         Delta = SkHwtRead(pAC,Ioc) ;
259         ppLast = &pAC->Tim.StQueue ;
260         pTm = pAC->Tim.StQueue ;
261         while (pTm && !Done) {
262                 if (Delta >= pTm->TmDelta) {
263                         /* Timer ran out */
264                         pTm->TmActive = SK_FALSE ;
265                         Delta -= pTm->TmDelta ;
266                         ppLast = &pTm->TmNext ;
267                         pTm = pTm->TmNext ;
268                 } else {
269                         /* We found the first timer that did not run out */
270                         pTm->TmDelta -= Delta ;
271                         Delta = 0 ;
272                         Done = 1 ;
273                 }
274         }
275         *ppLast = 0 ;
276         /*
277          * pTm points to the first Timer that did not run out.
278          * StQueue points to the first Timer that run out.
279          */
280
281         for ( pTComp = pAC->Tim.StQueue ; pTComp ; pTComp = pTComp->TmNext) {
282                 SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent,
283                         pTComp->TmPara) ;
284         }
285
286         /* Set head of timer queue to the first timer that did not run out */
287         pAC->Tim.StQueue = pTm ;
288
289         if (Restart && pAC->Tim.StQueue) {
290                 /* Restart HW timer */
291                 SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ;
292         }
293 }
294
295 #endif /* CONFIG_SK98 */
296
297 /* End of file */