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*/ 80static 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 */ 93intro() 94{} 95#endif 96 97 98/* Forward declaration */ 99static 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 */ 107void SkTimerInit( 108SK_AC *pAC, /* Adapters context */ 109SK_IOC Ioc, /* IoContext */ 110int 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 */ 129void SkTimerStop( 130SK_AC *pAC, /* Adapters context */ 131SK_IOC Ioc, /* IoContext */ 132SK_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 */ 166void SkTimerStart( 167SK_AC *pAC, /* Adapters context */ 168SK_IOC Ioc, /* IoContext */ 169SK_TIMER *pTimer, /* Timer Pointer to be started */ 170SK_U32 Time, /* Time value */ 171SK_U32 Class, /* Event Class for this timer */ 172SK_U32 Event, /* Event Value for this timer */ 173SK_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 237void SkTimerDone( 238SK_AC *pAC, /* Adapters context */ 239SK_IOC Ioc) /* IoContext */ 240{ 241 timer_done(pAC,Ioc,1) ; 242} 243 244 245static void timer_done( 246SK_AC *pAC, /* Adapters context */ 247SK_IOC Ioc, /* IoContext */ 248int 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 */ 294