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