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 static void timer_done(struct s_smc *smc, int restart); 22 23 void smt_timer_init(struct s_smc *smc) 24 { 25 smc->t.st_queue = NULL; 26 smc->t.st_fast.tm_active = FALSE ; 27 smc->t.st_fast.tm_next = NULL; 28 hwt_init(smc) ; 29 } 30 31 void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer) 32 { 33 struct smt_timer **prev ; 34 struct smt_timer *tm ; 35 36 /* 37 * remove timer from queue 38 */ 39 timer->tm_active = FALSE ; 40 if (smc->t.st_queue == timer && !timer->tm_next) { 41 hwt_stop(smc) ; 42 } 43 for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { 44 if (tm == timer) { 45 *prev = tm->tm_next ; 46 if (tm->tm_next) { 47 tm->tm_next->tm_delta += tm->tm_delta ; 48 } 49 return ; 50 } 51 } 52 } 53 54 void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time, 55 u_long token) 56 { 57 struct smt_timer **prev ; 58 struct smt_timer *tm ; 59 u_long delta = 0 ; 60 61 time /= 16 ; /* input is uS, clock ticks are 16uS */ 62 if (!time) 63 time = 1 ; 64 smt_timer_stop(smc,timer) ; 65 timer->tm_smc = smc ; 66 timer->tm_token = token ; 67 timer->tm_active = TRUE ; 68 if (!smc->t.st_queue) { 69 smc->t.st_queue = timer ; 70 timer->tm_next = NULL; 71 timer->tm_delta = time ; 72 hwt_start(smc,time) ; 73 return ; 74 } 75 /* 76 * timer correction 77 */ 78 timer_done(smc,0) ; 79 80 /* 81 * find position in queue 82 */ 83 delta = 0 ; 84 for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) { 85 if (delta + tm->tm_delta > time) { 86 break ; 87 } 88 delta += tm->tm_delta ; 89 } 90 /* insert in queue */ 91 *prev = timer ; 92 timer->tm_next = tm ; 93 timer->tm_delta = time - delta ; 94 if (tm) 95 tm->tm_delta -= timer->tm_delta ; 96 /* 97 * start new with first 98 */ 99 hwt_start(smc,smc->t.st_queue->tm_delta) ; 100 } 101 102 void smt_force_irq(struct s_smc *smc) 103 { 104 smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST)); 105 } 106 107 void smt_timer_done(struct s_smc *smc) 108 { 109 timer_done(smc,1) ; 110 } 111 112 static void timer_done(struct s_smc *smc, int restart) 113 { 114 u_long delta ; 115 struct smt_timer *tm ; 116 struct smt_timer *next ; 117 struct smt_timer **last ; 118 int done = 0 ; 119 120 delta = hwt_read(smc) ; 121 last = &smc->t.st_queue ; 122 tm = smc->t.st_queue ; 123 while (tm && !done) { 124 if (delta >= tm->tm_delta) { 125 tm->tm_active = FALSE ; 126 delta -= tm->tm_delta ; 127 last = &tm->tm_next ; 128 tm = tm->tm_next ; 129 } 130 else { 131 tm->tm_delta -= delta ; 132 delta = 0 ; 133 done = 1 ; 134 } 135 } 136 *last = NULL; 137 next = smc->t.st_queue ; 138 smc->t.st_queue = tm ; 139 140 for ( tm = next ; tm ; tm = next) { 141 next = tm->tm_next ; 142 timer_event(smc,tm->tm_token) ; 143 } 144 145 if (restart && smc->t.st_queue) 146 hwt_start(smc,smc->t.st_queue->tm_delta) ; 147 } 148 149