1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
233f810b2SJeff Kirsher /******************************************************************************
333f810b2SJeff Kirsher *
433f810b2SJeff Kirsher * (C)Copyright 1998,1999 SysKonnect,
533f810b2SJeff Kirsher * a business unit of Schneider & Koch & Co. Datensysteme GmbH.
633f810b2SJeff Kirsher *
733f810b2SJeff Kirsher * See the file "skfddi.c" for further information.
833f810b2SJeff Kirsher *
933f810b2SJeff Kirsher * The information in this file is provided "AS IS" without warranty.
1033f810b2SJeff Kirsher *
1133f810b2SJeff Kirsher ******************************************************************************/
1233f810b2SJeff Kirsher
1333f810b2SJeff Kirsher /*
1433f810b2SJeff Kirsher SMT timer
1533f810b2SJeff Kirsher */
1633f810b2SJeff Kirsher
1733f810b2SJeff Kirsher #include "h/types.h"
1833f810b2SJeff Kirsher #include "h/fddi.h"
1933f810b2SJeff Kirsher #include "h/smc.h"
2033f810b2SJeff Kirsher
2133f810b2SJeff Kirsher static void timer_done(struct s_smc *smc, int restart);
2233f810b2SJeff Kirsher
smt_timer_init(struct s_smc * smc)2333f810b2SJeff Kirsher void smt_timer_init(struct s_smc *smc)
2433f810b2SJeff Kirsher {
2533f810b2SJeff Kirsher smc->t.st_queue = NULL;
2633f810b2SJeff Kirsher smc->t.st_fast.tm_active = FALSE ;
2733f810b2SJeff Kirsher smc->t.st_fast.tm_next = NULL;
2833f810b2SJeff Kirsher hwt_init(smc) ;
2933f810b2SJeff Kirsher }
3033f810b2SJeff Kirsher
smt_timer_stop(struct s_smc * smc,struct smt_timer * timer)3133f810b2SJeff Kirsher void smt_timer_stop(struct s_smc *smc, struct smt_timer *timer)
3233f810b2SJeff Kirsher {
3333f810b2SJeff Kirsher struct smt_timer **prev ;
3433f810b2SJeff Kirsher struct smt_timer *tm ;
3533f810b2SJeff Kirsher
3633f810b2SJeff Kirsher /*
3733f810b2SJeff Kirsher * remove timer from queue
3833f810b2SJeff Kirsher */
3933f810b2SJeff Kirsher timer->tm_active = FALSE ;
4033f810b2SJeff Kirsher if (smc->t.st_queue == timer && !timer->tm_next) {
4133f810b2SJeff Kirsher hwt_stop(smc) ;
4233f810b2SJeff Kirsher }
4333f810b2SJeff Kirsher for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
4433f810b2SJeff Kirsher if (tm == timer) {
4533f810b2SJeff Kirsher *prev = tm->tm_next ;
4633f810b2SJeff Kirsher if (tm->tm_next) {
4733f810b2SJeff Kirsher tm->tm_next->tm_delta += tm->tm_delta ;
4833f810b2SJeff Kirsher }
4933f810b2SJeff Kirsher return ;
5033f810b2SJeff Kirsher }
5133f810b2SJeff Kirsher }
5233f810b2SJeff Kirsher }
5333f810b2SJeff Kirsher
smt_timer_start(struct s_smc * smc,struct smt_timer * timer,u_long time,u_long token)5433f810b2SJeff Kirsher void smt_timer_start(struct s_smc *smc, struct smt_timer *timer, u_long time,
5533f810b2SJeff Kirsher u_long token)
5633f810b2SJeff Kirsher {
5733f810b2SJeff Kirsher struct smt_timer **prev ;
5833f810b2SJeff Kirsher struct smt_timer *tm ;
5933f810b2SJeff Kirsher u_long delta = 0 ;
6033f810b2SJeff Kirsher
6133f810b2SJeff Kirsher time /= 16 ; /* input is uS, clock ticks are 16uS */
6233f810b2SJeff Kirsher if (!time)
6333f810b2SJeff Kirsher time = 1 ;
6433f810b2SJeff Kirsher smt_timer_stop(smc,timer) ;
6533f810b2SJeff Kirsher timer->tm_smc = smc ;
6633f810b2SJeff Kirsher timer->tm_token = token ;
6733f810b2SJeff Kirsher timer->tm_active = TRUE ;
6833f810b2SJeff Kirsher if (!smc->t.st_queue) {
6933f810b2SJeff Kirsher smc->t.st_queue = timer ;
7033f810b2SJeff Kirsher timer->tm_next = NULL;
7133f810b2SJeff Kirsher timer->tm_delta = time ;
7233f810b2SJeff Kirsher hwt_start(smc,time) ;
7333f810b2SJeff Kirsher return ;
7433f810b2SJeff Kirsher }
7533f810b2SJeff Kirsher /*
7633f810b2SJeff Kirsher * timer correction
7733f810b2SJeff Kirsher */
7833f810b2SJeff Kirsher timer_done(smc,0) ;
7933f810b2SJeff Kirsher
8033f810b2SJeff Kirsher /*
8133f810b2SJeff Kirsher * find position in queue
8233f810b2SJeff Kirsher */
8333f810b2SJeff Kirsher delta = 0 ;
8433f810b2SJeff Kirsher for (prev = &smc->t.st_queue ; (tm = *prev) ; prev = &tm->tm_next ) {
8533f810b2SJeff Kirsher if (delta + tm->tm_delta > time) {
8633f810b2SJeff Kirsher break ;
8733f810b2SJeff Kirsher }
8833f810b2SJeff Kirsher delta += tm->tm_delta ;
8933f810b2SJeff Kirsher }
9033f810b2SJeff Kirsher /* insert in queue */
9133f810b2SJeff Kirsher *prev = timer ;
9233f810b2SJeff Kirsher timer->tm_next = tm ;
9333f810b2SJeff Kirsher timer->tm_delta = time - delta ;
9433f810b2SJeff Kirsher if (tm)
9533f810b2SJeff Kirsher tm->tm_delta -= timer->tm_delta ;
9633f810b2SJeff Kirsher /*
9733f810b2SJeff Kirsher * start new with first
9833f810b2SJeff Kirsher */
9933f810b2SJeff Kirsher hwt_start(smc,smc->t.st_queue->tm_delta) ;
10033f810b2SJeff Kirsher }
10133f810b2SJeff Kirsher
smt_force_irq(struct s_smc * smc)10233f810b2SJeff Kirsher void smt_force_irq(struct s_smc *smc)
10333f810b2SJeff Kirsher {
10433f810b2SJeff Kirsher smt_timer_start(smc,&smc->t.st_fast,32L, EV_TOKEN(EVENT_SMT,SM_FAST));
10533f810b2SJeff Kirsher }
10633f810b2SJeff Kirsher
smt_timer_done(struct s_smc * smc)10733f810b2SJeff Kirsher void smt_timer_done(struct s_smc *smc)
10833f810b2SJeff Kirsher {
10933f810b2SJeff Kirsher timer_done(smc,1) ;
11033f810b2SJeff Kirsher }
11133f810b2SJeff Kirsher
timer_done(struct s_smc * smc,int restart)11233f810b2SJeff Kirsher static void timer_done(struct s_smc *smc, int restart)
11333f810b2SJeff Kirsher {
11433f810b2SJeff Kirsher u_long delta ;
11533f810b2SJeff Kirsher struct smt_timer *tm ;
11633f810b2SJeff Kirsher struct smt_timer *next ;
11733f810b2SJeff Kirsher struct smt_timer **last ;
11833f810b2SJeff Kirsher int done = 0 ;
11933f810b2SJeff Kirsher
12033f810b2SJeff Kirsher delta = hwt_read(smc) ;
12133f810b2SJeff Kirsher last = &smc->t.st_queue ;
12233f810b2SJeff Kirsher tm = smc->t.st_queue ;
12333f810b2SJeff Kirsher while (tm && !done) {
12433f810b2SJeff Kirsher if (delta >= tm->tm_delta) {
12533f810b2SJeff Kirsher tm->tm_active = FALSE ;
12633f810b2SJeff Kirsher delta -= tm->tm_delta ;
12733f810b2SJeff Kirsher last = &tm->tm_next ;
12833f810b2SJeff Kirsher tm = tm->tm_next ;
12933f810b2SJeff Kirsher }
13033f810b2SJeff Kirsher else {
13133f810b2SJeff Kirsher tm->tm_delta -= delta ;
13233f810b2SJeff Kirsher delta = 0 ;
13333f810b2SJeff Kirsher done = 1 ;
13433f810b2SJeff Kirsher }
13533f810b2SJeff Kirsher }
13633f810b2SJeff Kirsher *last = NULL;
13733f810b2SJeff Kirsher next = smc->t.st_queue ;
13833f810b2SJeff Kirsher smc->t.st_queue = tm ;
13933f810b2SJeff Kirsher
14033f810b2SJeff Kirsher for ( tm = next ; tm ; tm = next) {
14133f810b2SJeff Kirsher next = tm->tm_next ;
14233f810b2SJeff Kirsher timer_event(smc,tm->tm_token) ;
14333f810b2SJeff Kirsher }
14433f810b2SJeff Kirsher
14533f810b2SJeff Kirsher if (restart && smc->t.st_queue)
14633f810b2SJeff Kirsher hwt_start(smc,smc->t.st_queue->tm_delta) ;
14733f810b2SJeff Kirsher }
14833f810b2SJeff Kirsher
149