1// SPDX-License-Identifier: GPL-2.0-or-later 2/****************************************************************************** 3 * 4 * (C)Copyright 1998,1999 SysKonnect, 5 * a business unit of Schneider & Koch & Co. Datensysteme GmbH. 6 * 7 * See the file "skfddi.c" for further information. 8 * 9 * The information in this file is provided "AS IS" without warranty. 10 * 11 ******************************************************************************/ 12 13/* 14 SMT timer 15*/ 16 17#include "h/types.h" 18#include "h/fddi.h" 19#include "h/smc.h" 20 21#ifndef lint 22static const char ID_sccs[] = "@(#)smttimer.c 2.4 97/08/04 (C) SK " ; 23#endif 24 25static void timer_done(struct s_smc *smc, int restart); 26 27void smt_timer_init(struct s_smc *smc) 28{ 29 smc->t.st_queue = NULL; 30 smc->t.st_fast.tm_active = FALSE ; 31 smc->t.st_fast.tm_next = NULL; 32 hwt_init(smc) ; 33} 34 35void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer) 36{ 37 struct smt_timer **prev ; 38 struct smt_timer *tm ; 39 40 /* 41 * remove timer from queue 42 */ 43 timer->tm_active = FALSE ; 44 if (smc->t.st_queue == timer && !timer->tm_next) { 45 hwt_stop(smc) ; 46 } 47 for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { 48 if (tm == timer) { 49 *prev = tm->tm_next ; 50 if (tm->tm_next) { 51 tm->tm_next->tm_delta += tm->tm_delta ; 52 } 53 return ; 54 } 55 } 56} 57 58void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time, 59 u_long token) 60{ 61 struct smt_timer **prev ; 62 struct smt_timer *tm ; 63 u_long delta = 0 ; 64 65 time /= 16 ; /* input is uS, clock ticks are 16uS */ 66 if (!time) 67 time = 1 ; 68 smt_timer_stop(smc,timer) ; 69 timer->tm_smc = smc ; 70 timer->tm_token = token ; 71 timer->tm_active = TRUE ; 72 if (!smc->t.st_queue) { 73 smc->t.st_queue = timer ; 74 timer->tm_next = NULL; 75 timer->tm_delta = time ; 76 hwt_start(smc,time) ; 77 return ; 78 } 79 /* 80 * timer correction 81 */ 82 timer_done(smc,0) ; 83 84 /* 85 * find position in queue 86 */ 87 delta = 0 ; 88 for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { 89 if (delta + tm->tm_delta > time) { 90 break ; 91 } 92 delta += tm->tm_delta ; 93 } 94 /* insert in queue */ 95 *prev = timer ; 96 timer->tm_next = tm ; 97 timer->tm_delta = time - delta ; 98 if (tm) 99 tm->tm_delta -= timer->tm_delta ; 100 /* 101 * start new with first 102 */ 103 hwt_start(smc,smc->t.st_queue->tm_delta) ; 104} 105 106void smt_force_irq(struct s_smc *smc) 107{ 108 smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); 109} 110 111void smt_timer_done(struct s_smc *smc) 112{ 113 timer_done(smc,1) ; 114} 115 116static void timer_done(struct s_smc *smc, int restart) 117{ 118 u_long delta ; 119 struct smt_timer *tm ; 120 struct smt_timer *next ; 121 struct smt_timer **last ; 122 int done = 0 ; 123 124 delta = hwt_read(smc) ; 125 last = &smc->t.st_queue ; 126 tm = smc->t.st_queue ; 127 while (tm && !done) { 128 if (delta >= tm->tm_delta) { 129 tm->tm_active = FALSE ; 130 delta -= tm->tm_delta ; 131 last = &tm->tm_next ; 132 tm = tm->tm_next ; 133 } 134 else { 135 tm->tm_delta -= delta ; 136 delta = 0 ; 137 done = 1 ; 138 } 139 } 140 *last = NULL; 141 next = smc->t.st_queue ; 142 smc->t.st_queue = tm ; 143 144 for ( tm = next ; tm ; tm = next) { 145 next = tm->tm_next ; 146 timer_event(smc,tm->tm_token) ; 147 } 148 149 if (restart && smc->t.st_queue) 150 hwt_start(smc,smc->t.st_queue->tm_delta) ; 151} 152 153