xref: /openbmc/linux/drivers/net/fddi/skfp/smttimer.c (revision cdd38c5f1ce4398ec58fec95904b75824daab7b5)
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