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