xref: /kernel/linux/linux-5.10/drivers/net/fddi/skfp/rmt.c (revision 8c2ecf20)
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 RMT
15	Ring Management
16*/
17
18/*
19 * Hardware independent state machine implemantation
20 * The following external SMT functions are referenced :
21 *
22 * 		queue_event()
23 * 		smt_timer_start()
24 * 		smt_timer_stop()
25 *
26 * 	The following external HW dependent functions are referenced :
27 *		sm_ma_control()
28 *		sm_mac_check_beacon_claim()
29 *
30 * 	The following HW dependent events are required :
31 *		RM_RING_OP
32 *		RM_RING_NON_OP
33 *		RM_MY_BEACON
34 *		RM_OTHER_BEACON
35 *		RM_MY_CLAIM
36 *		RM_TRT_EXP
37 *		RM_VALID_CLAIM
38 *
39 */
40
41#include "h/types.h"
42#include "h/fddi.h"
43#include "h/smc.h"
44
45#define KERNEL
46#include "h/smtstate.h"
47
48#ifndef	lint
49static const char ID_sccs[] = "@(#)rmt.c	2.13 99/07/02 (C) SK " ;
50#endif
51
52/*
53 * FSM Macros
54 */
55#define AFLAG	0x10
56#define GO_STATE(x)	(smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)
57#define ACTIONS_DONE()	(smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)
58#define ACTIONS(x)	(x|AFLAG)
59
60#define RM0_ISOLATED	0
61#define RM1_NON_OP	1		/* not operational */
62#define RM2_RING_OP	2		/* ring operational */
63#define RM3_DETECT	3		/* detect dupl addresses */
64#define RM4_NON_OP_DUP	4		/* dupl. addr detected */
65#define RM5_RING_OP_DUP	5		/* ring oper. with dupl. addr */
66#define RM6_DIRECTED	6		/* sending directed beacons */
67#define RM7_TRACE	7		/* trace initiated */
68
69/*
70 * symbolic state names
71 */
72static const char * const rmt_states[] = {
73	"RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",
74	"RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",
75	"RM7_TRACE"
76} ;
77
78/*
79 * symbolic event names
80 */
81static const char * const rmt_events[] = {
82	"NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",
83	"RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",
84	"RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",
85	"RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",
86	"RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",
87	"RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"
88} ;
89
90/*
91 * Globals
92 * in struct s_rmt
93 */
94
95
96/*
97 * function declarations
98 */
99static void rmt_fsm(struct s_smc *smc, int cmd);
100static void start_rmt_timer0(struct s_smc *smc, u_long value, int event);
101static void start_rmt_timer1(struct s_smc *smc, u_long value, int event);
102static void start_rmt_timer2(struct s_smc *smc, u_long value, int event);
103static void stop_rmt_timer0(struct s_smc *smc);
104static void stop_rmt_timer1(struct s_smc *smc);
105static void stop_rmt_timer2(struct s_smc *smc);
106static void rmt_dup_actions(struct s_smc *smc);
107static void rmt_reinsert_actions(struct s_smc *smc);
108static void rmt_leave_actions(struct s_smc *smc);
109static void rmt_new_dup_actions(struct s_smc *smc);
110
111#ifndef SUPERNET_3
112extern void restart_trt_for_dbcn() ;
113#endif /*SUPERNET_3*/
114
115/*
116	init RMT state machine
117	clear all RMT vars and flags
118*/
119void rmt_init(struct s_smc *smc)
120{
121	smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;
122	smc->r.dup_addr_test = DA_NONE ;
123	smc->r.da_flag = 0 ;
124	smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
125	smc->r.sm_ma_avail = FALSE ;
126	smc->r.loop_avail = 0 ;
127	smc->r.bn_flag = 0 ;
128	smc->r.jm_flag = 0 ;
129	smc->r.no_flag = TRUE ;
130}
131
132/*
133	RMT state machine
134	called by dispatcher
135
136	do
137		display state change
138		process event
139	until SM is stable
140*/
141void rmt(struct s_smc *smc, int event)
142{
143	int	state ;
144
145	do {
146		DB_RMT("RMT : state %s%s event %s",
147		       smc->mib.m[MAC0].fddiMACRMTState & AFLAG ? "ACTIONS " : "",
148		       rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG],
149		       rmt_events[event]);
150		state = smc->mib.m[MAC0].fddiMACRMTState ;
151		rmt_fsm(smc,event) ;
152		event = 0 ;
153	} while (state != smc->mib.m[MAC0].fddiMACRMTState) ;
154	rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;
155}
156
157/*
158	process RMT event
159*/
160static void rmt_fsm(struct s_smc *smc, int cmd)
161{
162	/*
163	 * RM00-RM70 : from all states
164	 */
165	if (!smc->r.rm_join && !smc->r.rm_loop &&
166		smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&
167		smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {
168		RS_SET(smc,RS_NORINGOP) ;
169		rmt_indication(smc,0) ;
170		GO_STATE(RM0_ISOLATED) ;
171		return ;
172	}
173
174	switch(smc->mib.m[MAC0].fddiMACRMTState) {
175	case ACTIONS(RM0_ISOLATED) :
176		stop_rmt_timer0(smc) ;
177		stop_rmt_timer1(smc) ;
178		stop_rmt_timer2(smc) ;
179
180		/*
181		 * Disable MAC.
182		 */
183		sm_ma_control(smc,MA_OFFLINE) ;
184		smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
185		smc->r.loop_avail = FALSE ;
186		smc->r.sm_ma_avail = FALSE ;
187		smc->r.no_flag = TRUE ;
188		DB_RMTN(1, "RMT : ISOLATED");
189		ACTIONS_DONE() ;
190		break ;
191	case RM0_ISOLATED :
192		/*RM01*/
193		if (smc->r.rm_join || smc->r.rm_loop) {
194			/*
195			 * According to the standard the MAC must be reset
196			 * here. The FORMAC will be initialized and Claim
197			 * and Beacon Frames will be uploaded to the MAC.
198			 * So any change of Treq will take effect NOW.
199			 */
200			sm_ma_control(smc,MA_RESET) ;
201			GO_STATE(RM1_NON_OP) ;
202			break ;
203		}
204		break ;
205	case ACTIONS(RM1_NON_OP) :
206		start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;
207		stop_rmt_timer1(smc) ;
208		stop_rmt_timer2(smc) ;
209		sm_ma_control(smc,MA_BEACON) ;
210		DB_RMTN(1, "RMT : RING DOWN");
211		RS_SET(smc,RS_NORINGOP) ;
212		smc->r.sm_ma_avail = FALSE ;
213		rmt_indication(smc,0) ;
214		ACTIONS_DONE() ;
215		break ;
216	case RM1_NON_OP :
217		/*RM12*/
218		if (cmd == RM_RING_OP) {
219			RS_SET(smc,RS_RINGOPCHANGE) ;
220			GO_STATE(RM2_RING_OP) ;
221			break ;
222		}
223		/*RM13*/
224		else if (cmd == RM_TIMEOUT_NON_OP) {
225			smc->r.bn_flag = FALSE ;
226			smc->r.no_flag = TRUE ;
227			GO_STATE(RM3_DETECT) ;
228			break ;
229		}
230		break ;
231	case ACTIONS(RM2_RING_OP) :
232		stop_rmt_timer0(smc) ;
233		stop_rmt_timer1(smc) ;
234		stop_rmt_timer2(smc) ;
235		smc->r.no_flag = FALSE ;
236		if (smc->r.rm_loop)
237			smc->r.loop_avail = TRUE ;
238		if (smc->r.rm_join) {
239			smc->r.sm_ma_avail = TRUE ;
240			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
241			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
242				else
243			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
244		}
245		DB_RMTN(1, "RMT : RING UP");
246		RS_CLEAR(smc,RS_NORINGOP) ;
247		RS_SET(smc,RS_RINGOPCHANGE) ;
248		rmt_indication(smc,1) ;
249		smt_stat_counter(smc,0) ;
250		ACTIONS_DONE() ;
251		break ;
252	case RM2_RING_OP :
253		/*RM21*/
254		if (cmd == RM_RING_NON_OP) {
255			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
256			smc->r.loop_avail = FALSE ;
257			RS_SET(smc,RS_RINGOPCHANGE) ;
258			GO_STATE(RM1_NON_OP) ;
259			break ;
260		}
261		/*RM22a*/
262		else if (cmd == RM_ENABLE_FLAG) {
263			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
264			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
265				else
266			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
267		}
268		/*RM25*/
269		else if (smc->r.dup_addr_test == DA_FAILED) {
270			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
271			smc->r.loop_avail = FALSE ;
272			smc->r.da_flag = TRUE ;
273			GO_STATE(RM5_RING_OP_DUP) ;
274			break ;
275		}
276		break ;
277	case ACTIONS(RM3_DETECT) :
278		start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;
279		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
280		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
281		sm_mac_check_beacon_claim(smc) ;
282		DB_RMTN(1, "RMT : RM3_DETECT");
283		ACTIONS_DONE() ;
284		break ;
285	case RM3_DETECT :
286		if (cmd == RM_TIMEOUT_POLL) {
287			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
288			sm_mac_check_beacon_claim(smc) ;
289			break ;
290		}
291		if (cmd == RM_TIMEOUT_D_MAX) {
292			smc->r.timer0_exp = TRUE ;
293		}
294		/*
295		 *jd(22-Feb-1999)
296		 * We need a time ">= 2*mac_d_max" since we had finished
297		 * Claim or Beacon state. So we will restart timer0 at
298		 * every state change.
299		 */
300		if (cmd == RM_TX_STATE_CHANGE) {
301			start_rmt_timer0(smc,
302					 smc->s.mac_d_max*2,
303					 RM_TIMEOUT_D_MAX) ;
304		}
305		/*RM32*/
306		if (cmd == RM_RING_OP) {
307			GO_STATE(RM2_RING_OP) ;
308			break ;
309		}
310		/*RM33a*/
311		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)
312			&& smc->r.bn_flag) {
313			smc->r.bn_flag = FALSE ;
314		}
315		/*RM33b*/
316		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
317			int	tx ;
318			/*
319			 * set bn_flag only if in state T4 or T5:
320			 * only if we're the beaconer should we start the
321			 * trace !
322			 */
323			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
324			DB_RMTN(2, "RMT : DETECT && TRT_EXPIRED && T4/T5");
325				smc->r.bn_flag = TRUE ;
326				/*
327				 * If one of the upstream stations beaconed
328				 * and the link to the upstream neighbor is
329				 * lost we need to restart the stuck timer to
330				 * check the "stuck beacon" condition.
331				 */
332				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
333					RM_TIMEOUT_T_STUCK) ;
334			}
335			/*
336			 * We do NOT need to clear smc->r.bn_flag in case of
337			 * not being in state T4 or T5, because the flag
338			 * must be cleared in order to get in this condition.
339			 */
340
341			DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",
342				tx, smc->r.bn_flag);
343		}
344		/*RM34a*/
345		else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {
346			rmt_new_dup_actions(smc) ;
347			GO_STATE(RM4_NON_OP_DUP) ;
348			break ;
349		}
350		/*RM34b*/
351		else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
352			rmt_new_dup_actions(smc) ;
353			GO_STATE(RM4_NON_OP_DUP) ;
354			break ;
355		}
356		/*RM34c*/
357		else if (cmd == RM_VALID_CLAIM) {
358			rmt_new_dup_actions(smc) ;
359			GO_STATE(RM4_NON_OP_DUP) ;
360			break ;
361		}
362		/*RM36*/
363		else if (cmd == RM_TIMEOUT_T_STUCK &&
364			smc->r.rm_join && smc->r.bn_flag) {
365			GO_STATE(RM6_DIRECTED) ;
366			break ;
367		}
368		break ;
369	case ACTIONS(RM4_NON_OP_DUP) :
370		start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);
371		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
372		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
373		sm_mac_check_beacon_claim(smc) ;
374		DB_RMTN(1, "RMT : RM4_NON_OP_DUP");
375		ACTIONS_DONE() ;
376		break ;
377	case RM4_NON_OP_DUP :
378		if (cmd == RM_TIMEOUT_POLL) {
379			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
380			sm_mac_check_beacon_claim(smc) ;
381			break ;
382		}
383		/*RM41*/
384		if (!smc->r.da_flag) {
385			GO_STATE(RM1_NON_OP) ;
386			break ;
387		}
388		/*RM44a*/
389		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
390			smc->r.bn_flag) {
391			smc->r.bn_flag = FALSE ;
392		}
393		/*RM44b*/
394		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
395			int	tx ;
396			/*
397			 * set bn_flag only if in state T4 or T5:
398			 * only if we're the beaconer should we start the
399			 * trace !
400			 */
401			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
402			DB_RMTN(2, "RMT : NOPDUP && TRT_EXPIRED && T4/T5");
403				smc->r.bn_flag = TRUE ;
404				/*
405				 * If one of the upstream stations beaconed
406				 * and the link to the upstream neighbor is
407				 * lost we need to restart the stuck timer to
408				 * check the "stuck beacon" condition.
409				 */
410				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
411					RM_TIMEOUT_T_STUCK) ;
412			}
413			/*
414			 * We do NOT need to clear smc->r.bn_flag in case of
415			 * not being in state T4 or T5, because the flag
416			 * must be cleared in order to get in this condition.
417			 */
418
419			DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",
420				tx, smc->r.bn_flag);
421		}
422		/*RM44c*/
423		else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {
424			rmt_dup_actions(smc) ;
425		}
426		/*RM45*/
427		else if (cmd == RM_RING_OP) {
428			smc->r.no_flag = FALSE ;
429			GO_STATE(RM5_RING_OP_DUP) ;
430			break ;
431		}
432		/*RM46*/
433		else if (cmd == RM_TIMEOUT_T_STUCK &&
434			smc->r.rm_join && smc->r.bn_flag) {
435			GO_STATE(RM6_DIRECTED) ;
436			break ;
437		}
438		break ;
439	case ACTIONS(RM5_RING_OP_DUP) :
440		stop_rmt_timer0(smc) ;
441		stop_rmt_timer1(smc) ;
442		stop_rmt_timer2(smc) ;
443		DB_RMTN(1, "RMT : RM5_RING_OP_DUP");
444		ACTIONS_DONE() ;
445		break;
446	case RM5_RING_OP_DUP :
447		/*RM52*/
448		if (smc->r.dup_addr_test == DA_PASSED) {
449			smc->r.da_flag = FALSE ;
450			GO_STATE(RM2_RING_OP) ;
451			break ;
452		}
453		/*RM54*/
454		else if (cmd == RM_RING_NON_OP) {
455			smc->r.jm_flag = FALSE ;
456			smc->r.bn_flag = FALSE ;
457			GO_STATE(RM4_NON_OP_DUP) ;
458			break ;
459		}
460		break ;
461	case ACTIONS(RM6_DIRECTED) :
462		start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;
463		stop_rmt_timer1(smc) ;
464		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
465		sm_ma_control(smc,MA_DIRECTED) ;
466		RS_SET(smc,RS_BEACON) ;
467		DB_RMTN(1, "RMT : RM6_DIRECTED");
468		ACTIONS_DONE() ;
469		break ;
470	case RM6_DIRECTED :
471		/*RM63*/
472		if (cmd == RM_TIMEOUT_POLL) {
473			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
474			sm_mac_check_beacon_claim(smc) ;
475#ifndef SUPERNET_3
476			/* Because of problems with the Supernet II chip set
477			 * sending of Directed Beacon will stop after 165ms
478			 * therefore restart_trt_for_dbcn(smc) will be called
479			 * to prevent this.
480			 */
481			restart_trt_for_dbcn(smc) ;
482#endif /*SUPERNET_3*/
483			break ;
484		}
485		if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
486			!smc->r.da_flag) {
487			smc->r.bn_flag = FALSE ;
488			GO_STATE(RM3_DETECT) ;
489			break ;
490		}
491		/*RM64*/
492		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
493			smc->r.da_flag) {
494			smc->r.bn_flag = FALSE ;
495			GO_STATE(RM4_NON_OP_DUP) ;
496			break ;
497		}
498		/*RM67*/
499		else if (cmd == RM_TIMEOUT_T_DIRECT) {
500			GO_STATE(RM7_TRACE) ;
501			break ;
502		}
503		break ;
504	case ACTIONS(RM7_TRACE) :
505		stop_rmt_timer0(smc) ;
506		stop_rmt_timer1(smc) ;
507		stop_rmt_timer2(smc) ;
508		smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;
509		queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
510		DB_RMTN(1, "RMT : RM7_TRACE");
511		ACTIONS_DONE() ;
512		break ;
513	case RM7_TRACE :
514		break ;
515	default:
516		SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;
517		break;
518	}
519}
520
521/*
522 * (jd) RMT duplicate address actions
523 * leave the ring or reinsert just as configured
524 */
525static void rmt_dup_actions(struct s_smc *smc)
526{
527	if (smc->r.jm_flag) {
528	}
529	else {
530		if (smc->s.rmt_dup_mac_behavior) {
531			SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
532                        rmt_reinsert_actions(smc) ;
533		}
534		else {
535			SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
536			rmt_leave_actions(smc) ;
537		}
538	}
539}
540
541/*
542 * Reconnect to the Ring
543 */
544static void rmt_reinsert_actions(struct s_smc *smc)
545{
546	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
547	queue_event(smc,EVENT_ECM,EC_CONNECT) ;
548}
549
550/*
551 * duplicate address detected
552 */
553static void rmt_new_dup_actions(struct s_smc *smc)
554{
555	smc->r.da_flag = TRUE ;
556	smc->r.bn_flag = FALSE ;
557	smc->r.jm_flag = FALSE ;
558	/*
559	 * we have three options : change address, jam or leave
560	 * we leave the ring as default
561	 * Optionally it's possible to reinsert after leaving the Ring
562	 * but this will not conform with SMT Spec.
563	 */
564	if (smc->s.rmt_dup_mac_behavior) {
565		SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
566		rmt_reinsert_actions(smc) ;
567	}
568	else {
569		SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
570		rmt_leave_actions(smc) ;
571	}
572}
573
574
575/*
576 * leave the ring
577 */
578static void rmt_leave_actions(struct s_smc *smc)
579{
580	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
581	/*
582	 * Note: Do NOT try again later. (with please reconnect)
583	 * The station must be left from the ring!
584	 */
585}
586
587/*
588 * SMT timer interface
589 *	start RMT timer 0
590 */
591static void start_rmt_timer0(struct s_smc *smc, u_long value, int event)
592{
593	smc->r.timer0_exp = FALSE ;		/* clear timer event flag */
594	smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));
595}
596
597/*
598 * SMT timer interface
599 *	start RMT timer 1
600 */
601static void start_rmt_timer1(struct s_smc *smc, u_long value, int event)
602{
603	smc->r.timer1_exp = FALSE ;	/* clear timer event flag */
604	smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));
605}
606
607/*
608 * SMT timer interface
609 *	start RMT timer 2
610 */
611static void start_rmt_timer2(struct s_smc *smc, u_long value, int event)
612{
613	smc->r.timer2_exp = FALSE ;		/* clear timer event flag */
614	smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));
615}
616
617/*
618 * SMT timer interface
619 *	stop RMT timer 0
620 */
621static void stop_rmt_timer0(struct s_smc *smc)
622{
623	if (smc->r.rmt_timer0.tm_active)
624		smt_timer_stop(smc,&smc->r.rmt_timer0) ;
625}
626
627/*
628 * SMT timer interface
629 *	stop RMT timer 1
630 */
631static void stop_rmt_timer1(struct s_smc *smc)
632{
633	if (smc->r.rmt_timer1.tm_active)
634		smt_timer_stop(smc,&smc->r.rmt_timer1) ;
635}
636
637/*
638 * SMT timer interface
639 *	stop RMT timer 2
640 */
641static void stop_rmt_timer2(struct s_smc *smc)
642{
643	if (smc->r.rmt_timer2.tm_active)
644		smt_timer_stop(smc,&smc->r.rmt_timer2) ;
645}
646
647