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