| /****************************************************************************** |
| * |
| * Name: sktimer.c |
| * Project: GEnesis, PCI Gigabit Ethernet Adapter |
| * Version: $Revision: 1.12 $ |
| * Date: $Date: 1999/11/22 13:38:51 $ |
| * Purpose: High level timer functions. |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| * |
| * (C)Copyright 1998,1999 SysKonnect, |
| * a business unit of Schneider & Koch & Co. Datensysteme GmbH. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * The information in this file is provided "AS IS" without warranty. |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| * |
| * History: |
| * |
| * $Log: sktimer.c,v $ |
| * Revision 1.12 1999/11/22 13:38:51 cgoos |
| * Changed license header to GPL. |
| * |
| * Revision 1.11 1998/12/17 13:24:13 gklug |
| * fix: restart problem: do NOT destroy timer queue if init 1 is done |
| * |
| * Revision 1.10 1998/10/15 15:11:36 gklug |
| * fix: ID_sccs to SysKonnectFileId |
| * |
| * Revision 1.9 1998/09/15 15:15:04 cgoos |
| * Changed TRUE/FALSE to SK_TRUE/SK_FALSE |
| * |
| * Revision 1.8 1998/09/08 08:47:55 gklug |
| * add: init level handling |
| * |
| * Revision 1.7 1998/08/19 09:50:53 gklug |
| * fix: remove struct keyword from c-code (see CCC) add typedefs |
| * |
| * Revision 1.6 1998/08/17 13:43:13 gklug |
| * chg: Parameter will be union of 64bit para, 2 times SK_U32 or SK_PTR |
| * |
| * Revision 1.5 1998/08/14 07:09:14 gklug |
| * fix: chg pAc -> pAC |
| * |
| * Revision 1.4 1998/08/07 12:53:46 gklug |
| * fix: first compiled version |
| * |
| * Revision 1.3 1998/08/07 09:31:53 gklug |
| * fix: delta spelling |
| * |
| * Revision 1.2 1998/08/07 09:31:02 gklug |
| * adapt functions to new c coding conventions |
| * rmv: "fast" handling |
| * chg: inserting of new timer in queue. |
| * chg: event queue generation when timer runs out |
| * |
| * Revision 1.1 1998/08/05 11:27:55 gklug |
| * first version: adapted from SMT |
| * |
| * |
| * |
| * |
| ******************************************************************************/ |
| |
| |
| #include <config.h> |
| |
| #ifdef CONFIG_SK98 |
| |
| /* |
| Event queue and dispatcher |
| */ |
| static const char SysKonnectFileId[] = |
| "$Header: /usr56/projects/ge/schedule/sktimer.c,v 1.12 1999/11/22 13:38:51 cgoos Exp $" ; |
| |
| #include "h/skdrv1st.h" /* Driver Specific Definitions */ |
| #include "h/skdrv2nd.h" /* Adapter Control- and Driver specific Def. */ |
| |
| #ifdef __C2MAN__ |
| /* |
| Event queue management. |
| |
| General Description: |
| |
| */ |
| intro() |
| {} |
| #endif |
| |
| |
| /* Forward declaration */ |
| static void timer_done(SK_AC *pAC,SK_IOC Ioc,int Restart); |
| |
| |
| /* |
| * Inits the software timer |
| * |
| * needs to be called during Init level 1. |
| */ |
| void SkTimerInit( |
| SK_AC *pAC, /* Adapters context */ |
| SK_IOC Ioc, /* IoContext */ |
| int Level) /* Init Level */ |
| { |
| switch (Level) { |
| case SK_INIT_DATA: |
| pAC->Tim.StQueue = 0 ; |
| break; |
| case SK_INIT_IO: |
| SkHwtInit(pAC,Ioc) ; |
| SkTimerDone(pAC, Ioc); |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /* |
| * Stops a high level timer |
| * - If a timer is not in the queue the function returns normally, too. |
| */ |
| void SkTimerStop( |
| SK_AC *pAC, /* Adapters context */ |
| SK_IOC Ioc, /* IoContext */ |
| SK_TIMER *pTimer) /* Timer Pointer to be started */ |
| { |
| SK_TIMER **ppTimPrev ; |
| SK_TIMER *pTm ; |
| |
| /* |
| * remove timer from queue |
| */ |
| pTimer->TmActive = SK_FALSE ; |
| if (pAC->Tim.StQueue == pTimer && !pTimer->TmNext) { |
| SkHwtStop(pAC,Ioc) ; |
| } |
| for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ; |
| ppTimPrev = &pTm->TmNext ) { |
| if (pTm == pTimer) { |
| /* |
| * Timer found in queue |
| * - dequeue it and |
| * - correct delta of the next timer |
| */ |
| *ppTimPrev = pTm->TmNext ; |
| |
| if (pTm->TmNext) { |
| /* correct delta of next timer in queue */ |
| pTm->TmNext->TmDelta += pTm->TmDelta ; |
| } |
| return ; |
| } |
| } |
| } |
| |
| /* |
| * Start a high level software timer |
| */ |
| void SkTimerStart( |
| SK_AC *pAC, /* Adapters context */ |
| SK_IOC Ioc, /* IoContext */ |
| SK_TIMER *pTimer, /* Timer Pointer to be started */ |
| SK_U32 Time, /* Time value */ |
| SK_U32 Class, /* Event Class for this timer */ |
| SK_U32 Event, /* Event Value for this timer */ |
| SK_EVPARA Para) /* Event Parameter for this timer */ |
| { |
| SK_TIMER **ppTimPrev ; |
| SK_TIMER *pTm ; |
| SK_U32 Delta ; |
| |
| Time /= 16 ; /* input is uS, clock ticks are 16uS */ |
| if (!Time) |
| Time = 1 ; |
| |
| SkTimerStop(pAC,Ioc,pTimer) ; |
| |
| pTimer->TmClass = Class ; |
| pTimer->TmEvent = Event ; |
| pTimer->TmPara = Para ; |
| pTimer->TmActive = SK_TRUE ; |
| |
| if (!pAC->Tim.StQueue) { |
| /* First Timer to be started */ |
| pAC->Tim.StQueue = pTimer ; |
| pTimer->TmNext = 0 ; |
| pTimer->TmDelta = Time ; |
| SkHwtStart(pAC,Ioc,Time) ; |
| return ; |
| } |
| |
| /* |
| * timer correction |
| */ |
| timer_done(pAC,Ioc,0) ; |
| |
| /* |
| * find position in queue |
| */ |
| Delta = 0 ; |
| for (ppTimPrev = &pAC->Tim.StQueue ; (pTm = *ppTimPrev) ; |
| ppTimPrev = &pTm->TmNext ) { |
| if (Delta + pTm->TmDelta > Time) { |
| /* Position found */ |
| /* Here the timer needs to be inserted. */ |
| break ; |
| } |
| Delta += pTm->TmDelta ; |
| } |
| |
| /* insert in queue */ |
| *ppTimPrev = pTimer ; |
| pTimer->TmNext = pTm ; |
| pTimer->TmDelta = Time - Delta ; |
| |
| if (pTm) { |
| /* There is a next timer |
| * -> correct its Delta value. |
| */ |
| pTm->TmDelta -= pTimer->TmDelta ; |
| } |
| |
| /* |
| * start new with first |
| */ |
| SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ; |
| } |
| |
| |
| void SkTimerDone( |
| SK_AC *pAC, /* Adapters context */ |
| SK_IOC Ioc) /* IoContext */ |
| { |
| timer_done(pAC,Ioc,1) ; |
| } |
| |
| |
| static void timer_done( |
| SK_AC *pAC, /* Adapters context */ |
| SK_IOC Ioc, /* IoContext */ |
| int Restart) /* Do we need to restart the Hardware timer ? */ |
| { |
| SK_U32 Delta ; |
| SK_TIMER *pTm ; |
| SK_TIMER *pTComp ; /* Timer completed now now */ |
| SK_TIMER **ppLast ; /* Next field of Last timer to be deq */ |
| int Done = 0 ; |
| |
| Delta = SkHwtRead(pAC,Ioc) ; |
| ppLast = &pAC->Tim.StQueue ; |
| pTm = pAC->Tim.StQueue ; |
| while (pTm && !Done) { |
| if (Delta >= pTm->TmDelta) { |
| /* Timer ran out */ |
| pTm->TmActive = SK_FALSE ; |
| Delta -= pTm->TmDelta ; |
| ppLast = &pTm->TmNext ; |
| pTm = pTm->TmNext ; |
| } else { |
| /* We found the first timer that did not run out */ |
| pTm->TmDelta -= Delta ; |
| Delta = 0 ; |
| Done = 1 ; |
| } |
| } |
| *ppLast = 0 ; |
| /* |
| * pTm points to the first Timer that did not run out. |
| * StQueue points to the first Timer that run out. |
| */ |
| |
| for ( pTComp = pAC->Tim.StQueue ; pTComp ; pTComp = pTComp->TmNext) { |
| SkEventQueue(pAC,pTComp->TmClass, pTComp->TmEvent, |
| pTComp->TmPara) ; |
| } |
| |
| /* Set head of timer queue to the first timer that did not run out */ |
| pAC->Tim.StQueue = pTm ; |
| |
| if (Restart && pAC->Tim.StQueue) { |
| /* Restart HW timer */ |
| SkHwtStart(pAC,Ioc,pAC->Tim.StQueue->TmDelta) ; |
| } |
| } |
| |
| #endif /* CONFIG_SK98 */ |
| |
| /* End of file */ |