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