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