xref: /openbmc/linux/drivers/net/fddi/skfp/rmt.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
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 RMT
1533f810b2SJeff Kirsher 	Ring Management
1633f810b2SJeff Kirsher */
1733f810b2SJeff Kirsher 
1833f810b2SJeff Kirsher /*
1933f810b2SJeff Kirsher  * Hardware independent state machine implemantation
2033f810b2SJeff Kirsher  * The following external SMT functions are referenced :
2133f810b2SJeff Kirsher  *
2233f810b2SJeff Kirsher  * 		queue_event()
2333f810b2SJeff Kirsher  * 		smt_timer_start()
2433f810b2SJeff Kirsher  * 		smt_timer_stop()
2533f810b2SJeff Kirsher  *
2633f810b2SJeff Kirsher  * 	The following external HW dependent functions are referenced :
2733f810b2SJeff Kirsher  *		sm_ma_control()
2833f810b2SJeff Kirsher  *		sm_mac_check_beacon_claim()
2933f810b2SJeff Kirsher  *
3033f810b2SJeff Kirsher  * 	The following HW dependent events are required :
3133f810b2SJeff Kirsher  *		RM_RING_OP
3233f810b2SJeff Kirsher  *		RM_RING_NON_OP
3333f810b2SJeff Kirsher  *		RM_MY_BEACON
3433f810b2SJeff Kirsher  *		RM_OTHER_BEACON
3533f810b2SJeff Kirsher  *		RM_MY_CLAIM
3633f810b2SJeff Kirsher  *		RM_TRT_EXP
3733f810b2SJeff Kirsher  *		RM_VALID_CLAIM
3833f810b2SJeff Kirsher  *
3933f810b2SJeff Kirsher  */
4033f810b2SJeff Kirsher 
4133f810b2SJeff Kirsher #include "h/types.h"
4233f810b2SJeff Kirsher #include "h/fddi.h"
4333f810b2SJeff Kirsher #include "h/smc.h"
4433f810b2SJeff Kirsher 
4533f810b2SJeff Kirsher #define KERNEL
4633f810b2SJeff Kirsher #include "h/smtstate.h"
4733f810b2SJeff Kirsher 
4833f810b2SJeff Kirsher /*
4933f810b2SJeff Kirsher  * FSM Macros
5033f810b2SJeff Kirsher  */
5133f810b2SJeff Kirsher #define AFLAG	0x10
5233f810b2SJeff Kirsher #define GO_STATE(x)	(smc->mib.m[MAC0].fddiMACRMTState = (x)|AFLAG)
5333f810b2SJeff Kirsher #define ACTIONS_DONE()	(smc->mib.m[MAC0].fddiMACRMTState &= ~AFLAG)
5433f810b2SJeff Kirsher #define ACTIONS(x)	(x|AFLAG)
5533f810b2SJeff Kirsher 
5633f810b2SJeff Kirsher #define RM0_ISOLATED	0
5733f810b2SJeff Kirsher #define RM1_NON_OP	1		/* not operational */
5833f810b2SJeff Kirsher #define RM2_RING_OP	2		/* ring operational */
5933f810b2SJeff Kirsher #define RM3_DETECT	3		/* detect dupl addresses */
6033f810b2SJeff Kirsher #define RM4_NON_OP_DUP	4		/* dupl. addr detected */
6133f810b2SJeff Kirsher #define RM5_RING_OP_DUP	5		/* ring oper. with dupl. addr */
6233f810b2SJeff Kirsher #define RM6_DIRECTED	6		/* sending directed beacons */
6333f810b2SJeff Kirsher #define RM7_TRACE	7		/* trace initiated */
6433f810b2SJeff Kirsher 
6533f810b2SJeff Kirsher /*
6633f810b2SJeff Kirsher  * symbolic state names
6733f810b2SJeff Kirsher  */
6833f810b2SJeff Kirsher static const char * const rmt_states[] = {
6933f810b2SJeff Kirsher 	"RM0_ISOLATED","RM1_NON_OP","RM2_RING_OP","RM3_DETECT",
7033f810b2SJeff Kirsher 	"RM4_NON_OP_DUP","RM5_RING_OP_DUP","RM6_DIRECTED",
7133f810b2SJeff Kirsher 	"RM7_TRACE"
7233f810b2SJeff Kirsher } ;
7333f810b2SJeff Kirsher 
7433f810b2SJeff Kirsher /*
7533f810b2SJeff Kirsher  * symbolic event names
7633f810b2SJeff Kirsher  */
7733f810b2SJeff Kirsher static const char * const rmt_events[] = {
7833f810b2SJeff Kirsher 	"NONE","RM_RING_OP","RM_RING_NON_OP","RM_MY_BEACON",
7933f810b2SJeff Kirsher 	"RM_OTHER_BEACON","RM_MY_CLAIM","RM_TRT_EXP","RM_VALID_CLAIM",
8033f810b2SJeff Kirsher 	"RM_JOIN","RM_LOOP","RM_DUP_ADDR","RM_ENABLE_FLAG",
8133f810b2SJeff Kirsher 	"RM_TIMEOUT_NON_OP","RM_TIMEOUT_T_STUCK",
8233f810b2SJeff Kirsher 	"RM_TIMEOUT_ANNOUNCE","RM_TIMEOUT_T_DIRECT",
8333f810b2SJeff Kirsher 	"RM_TIMEOUT_D_MAX","RM_TIMEOUT_POLL","RM_TX_STATE_CHANGE"
8433f810b2SJeff Kirsher } ;
8533f810b2SJeff Kirsher 
8633f810b2SJeff Kirsher /*
8733f810b2SJeff Kirsher  * Globals
8833f810b2SJeff Kirsher  * in struct s_rmt
8933f810b2SJeff Kirsher  */
9033f810b2SJeff Kirsher 
9133f810b2SJeff Kirsher 
9233f810b2SJeff Kirsher /*
9333f810b2SJeff Kirsher  * function declarations
9433f810b2SJeff Kirsher  */
9533f810b2SJeff Kirsher static void rmt_fsm(struct s_smc *smc, int cmd);
9633f810b2SJeff Kirsher static void start_rmt_timer0(struct s_smc *smc, u_long value, int event);
9733f810b2SJeff Kirsher static void start_rmt_timer1(struct s_smc *smc, u_long value, int event);
9833f810b2SJeff Kirsher static void start_rmt_timer2(struct s_smc *smc, u_long value, int event);
9933f810b2SJeff Kirsher static void stop_rmt_timer0(struct s_smc *smc);
10033f810b2SJeff Kirsher static void stop_rmt_timer1(struct s_smc *smc);
10133f810b2SJeff Kirsher static void stop_rmt_timer2(struct s_smc *smc);
10233f810b2SJeff Kirsher static void rmt_dup_actions(struct s_smc *smc);
10333f810b2SJeff Kirsher static void rmt_reinsert_actions(struct s_smc *smc);
10433f810b2SJeff Kirsher static void rmt_leave_actions(struct s_smc *smc);
10533f810b2SJeff Kirsher static void rmt_new_dup_actions(struct s_smc *smc);
10633f810b2SJeff Kirsher 
10733f810b2SJeff Kirsher #ifndef SUPERNET_3
10833f810b2SJeff Kirsher extern void restart_trt_for_dbcn() ;
10933f810b2SJeff Kirsher #endif /*SUPERNET_3*/
11033f810b2SJeff Kirsher 
11133f810b2SJeff Kirsher /*
11233f810b2SJeff Kirsher 	init RMT state machine
11333f810b2SJeff Kirsher 	clear all RMT vars and flags
11433f810b2SJeff Kirsher */
rmt_init(struct s_smc * smc)11533f810b2SJeff Kirsher void rmt_init(struct s_smc *smc)
11633f810b2SJeff Kirsher {
11733f810b2SJeff Kirsher 	smc->mib.m[MAC0].fddiMACRMTState = ACTIONS(RM0_ISOLATED) ;
11833f810b2SJeff Kirsher 	smc->r.dup_addr_test = DA_NONE ;
11933f810b2SJeff Kirsher 	smc->r.da_flag = 0 ;
12033f810b2SJeff Kirsher 	smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
12133f810b2SJeff Kirsher 	smc->r.sm_ma_avail = FALSE ;
12233f810b2SJeff Kirsher 	smc->r.loop_avail = 0 ;
12333f810b2SJeff Kirsher 	smc->r.bn_flag = 0 ;
12433f810b2SJeff Kirsher 	smc->r.jm_flag = 0 ;
12533f810b2SJeff Kirsher 	smc->r.no_flag = TRUE ;
12633f810b2SJeff Kirsher }
12733f810b2SJeff Kirsher 
12833f810b2SJeff Kirsher /*
12933f810b2SJeff Kirsher 	RMT state machine
13033f810b2SJeff Kirsher 	called by dispatcher
13133f810b2SJeff Kirsher 
13233f810b2SJeff Kirsher 	do
13333f810b2SJeff Kirsher 		display state change
13433f810b2SJeff Kirsher 		process event
13533f810b2SJeff Kirsher 	until SM is stable
13633f810b2SJeff Kirsher */
rmt(struct s_smc * smc,int event)13733f810b2SJeff Kirsher void rmt(struct s_smc *smc, int event)
13833f810b2SJeff Kirsher {
13933f810b2SJeff Kirsher 	int	state ;
14033f810b2SJeff Kirsher 
14133f810b2SJeff Kirsher 	do {
1425671e8c1SJoe Perches 		DB_RMT("RMT : state %s%s event %s",
1435671e8c1SJoe Perches 		       smc->mib.m[MAC0].fddiMACRMTState & AFLAG ? "ACTIONS " : "",
1445671e8c1SJoe Perches 		       rmt_states[smc->mib.m[MAC0].fddiMACRMTState & ~AFLAG],
1455671e8c1SJoe Perches 		       rmt_events[event]);
14633f810b2SJeff Kirsher 		state = smc->mib.m[MAC0].fddiMACRMTState ;
14733f810b2SJeff Kirsher 		rmt_fsm(smc,event) ;
14833f810b2SJeff Kirsher 		event = 0 ;
14933f810b2SJeff Kirsher 	} while (state != smc->mib.m[MAC0].fddiMACRMTState) ;
15033f810b2SJeff Kirsher 	rmt_state_change(smc,(int)smc->mib.m[MAC0].fddiMACRMTState) ;
15133f810b2SJeff Kirsher }
15233f810b2SJeff Kirsher 
15333f810b2SJeff Kirsher /*
15433f810b2SJeff Kirsher 	process RMT event
15533f810b2SJeff Kirsher */
rmt_fsm(struct s_smc * smc,int cmd)15633f810b2SJeff Kirsher static void rmt_fsm(struct s_smc *smc, int cmd)
15733f810b2SJeff Kirsher {
15833f810b2SJeff Kirsher 	/*
15933f810b2SJeff Kirsher 	 * RM00-RM70 : from all states
16033f810b2SJeff Kirsher 	 */
16133f810b2SJeff Kirsher 	if (!smc->r.rm_join && !smc->r.rm_loop &&
16233f810b2SJeff Kirsher 		smc->mib.m[MAC0].fddiMACRMTState != ACTIONS(RM0_ISOLATED) &&
16333f810b2SJeff Kirsher 		smc->mib.m[MAC0].fddiMACRMTState != RM0_ISOLATED) {
16433f810b2SJeff Kirsher 		RS_SET(smc,RS_NORINGOP) ;
16533f810b2SJeff Kirsher 		rmt_indication(smc,0) ;
16633f810b2SJeff Kirsher 		GO_STATE(RM0_ISOLATED) ;
16733f810b2SJeff Kirsher 		return ;
16833f810b2SJeff Kirsher 	}
16933f810b2SJeff Kirsher 
17033f810b2SJeff Kirsher 	switch(smc->mib.m[MAC0].fddiMACRMTState) {
17133f810b2SJeff Kirsher 	case ACTIONS(RM0_ISOLATED) :
17233f810b2SJeff Kirsher 		stop_rmt_timer0(smc) ;
17333f810b2SJeff Kirsher 		stop_rmt_timer1(smc) ;
17433f810b2SJeff Kirsher 		stop_rmt_timer2(smc) ;
17533f810b2SJeff Kirsher 
17633f810b2SJeff Kirsher 		/*
17733f810b2SJeff Kirsher 		 * Disable MAC.
17833f810b2SJeff Kirsher 		 */
17933f810b2SJeff Kirsher 		sm_ma_control(smc,MA_OFFLINE) ;
18033f810b2SJeff Kirsher 		smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
18133f810b2SJeff Kirsher 		smc->r.loop_avail = FALSE ;
18233f810b2SJeff Kirsher 		smc->r.sm_ma_avail = FALSE ;
18333f810b2SJeff Kirsher 		smc->r.no_flag = TRUE ;
1845671e8c1SJoe Perches 		DB_RMTN(1, "RMT : ISOLATED");
18533f810b2SJeff Kirsher 		ACTIONS_DONE() ;
18633f810b2SJeff Kirsher 		break ;
18733f810b2SJeff Kirsher 	case RM0_ISOLATED :
18833f810b2SJeff Kirsher 		/*RM01*/
18933f810b2SJeff Kirsher 		if (smc->r.rm_join || smc->r.rm_loop) {
19033f810b2SJeff Kirsher 			/*
19133f810b2SJeff Kirsher 			 * According to the standard the MAC must be reset
19233f810b2SJeff Kirsher 			 * here. The FORMAC will be initialized and Claim
19333f810b2SJeff Kirsher 			 * and Beacon Frames will be uploaded to the MAC.
19433f810b2SJeff Kirsher 			 * So any change of Treq will take effect NOW.
19533f810b2SJeff Kirsher 			 */
19633f810b2SJeff Kirsher 			sm_ma_control(smc,MA_RESET) ;
19733f810b2SJeff Kirsher 			GO_STATE(RM1_NON_OP) ;
19833f810b2SJeff Kirsher 			break ;
19933f810b2SJeff Kirsher 		}
20033f810b2SJeff Kirsher 		break ;
20133f810b2SJeff Kirsher 	case ACTIONS(RM1_NON_OP) :
20233f810b2SJeff Kirsher 		start_rmt_timer0(smc,smc->s.rmt_t_non_op,RM_TIMEOUT_NON_OP) ;
20333f810b2SJeff Kirsher 		stop_rmt_timer1(smc) ;
20433f810b2SJeff Kirsher 		stop_rmt_timer2(smc) ;
20533f810b2SJeff Kirsher 		sm_ma_control(smc,MA_BEACON) ;
2065671e8c1SJoe Perches 		DB_RMTN(1, "RMT : RING DOWN");
20733f810b2SJeff Kirsher 		RS_SET(smc,RS_NORINGOP) ;
20833f810b2SJeff Kirsher 		smc->r.sm_ma_avail = FALSE ;
20933f810b2SJeff Kirsher 		rmt_indication(smc,0) ;
21033f810b2SJeff Kirsher 		ACTIONS_DONE() ;
21133f810b2SJeff Kirsher 		break ;
21233f810b2SJeff Kirsher 	case RM1_NON_OP :
21333f810b2SJeff Kirsher 		/*RM12*/
21433f810b2SJeff Kirsher 		if (cmd == RM_RING_OP) {
21533f810b2SJeff Kirsher 			RS_SET(smc,RS_RINGOPCHANGE) ;
21633f810b2SJeff Kirsher 			GO_STATE(RM2_RING_OP) ;
21733f810b2SJeff Kirsher 			break ;
21833f810b2SJeff Kirsher 		}
21933f810b2SJeff Kirsher 		/*RM13*/
22033f810b2SJeff Kirsher 		else if (cmd == RM_TIMEOUT_NON_OP) {
22133f810b2SJeff Kirsher 			smc->r.bn_flag = FALSE ;
22233f810b2SJeff Kirsher 			smc->r.no_flag = TRUE ;
22333f810b2SJeff Kirsher 			GO_STATE(RM3_DETECT) ;
22433f810b2SJeff Kirsher 			break ;
22533f810b2SJeff Kirsher 		}
22633f810b2SJeff Kirsher 		break ;
22733f810b2SJeff Kirsher 	case ACTIONS(RM2_RING_OP) :
22833f810b2SJeff Kirsher 		stop_rmt_timer0(smc) ;
22933f810b2SJeff Kirsher 		stop_rmt_timer1(smc) ;
23033f810b2SJeff Kirsher 		stop_rmt_timer2(smc) ;
23133f810b2SJeff Kirsher 		smc->r.no_flag = FALSE ;
23233f810b2SJeff Kirsher 		if (smc->r.rm_loop)
23333f810b2SJeff Kirsher 			smc->r.loop_avail = TRUE ;
23433f810b2SJeff Kirsher 		if (smc->r.rm_join) {
23533f810b2SJeff Kirsher 			smc->r.sm_ma_avail = TRUE ;
23633f810b2SJeff Kirsher 			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
23733f810b2SJeff Kirsher 				smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE;
23833f810b2SJeff Kirsher 			else
23933f810b2SJeff Kirsher 				smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE;
24033f810b2SJeff Kirsher 		}
2415671e8c1SJoe Perches 		DB_RMTN(1, "RMT : RING UP");
24233f810b2SJeff Kirsher 		RS_CLEAR(smc,RS_NORINGOP) ;
24333f810b2SJeff Kirsher 		RS_SET(smc,RS_RINGOPCHANGE) ;
24433f810b2SJeff Kirsher 		rmt_indication(smc,1) ;
24533f810b2SJeff Kirsher 		smt_stat_counter(smc,0) ;
24633f810b2SJeff Kirsher 		ACTIONS_DONE() ;
24733f810b2SJeff Kirsher 		break ;
24833f810b2SJeff Kirsher 	case RM2_RING_OP :
24933f810b2SJeff Kirsher 		/*RM21*/
25033f810b2SJeff Kirsher 		if (cmd == RM_RING_NON_OP) {
25133f810b2SJeff Kirsher 			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
25233f810b2SJeff Kirsher 			smc->r.loop_avail = FALSE ;
25333f810b2SJeff Kirsher 			RS_SET(smc,RS_RINGOPCHANGE) ;
25433f810b2SJeff Kirsher 			GO_STATE(RM1_NON_OP) ;
25533f810b2SJeff Kirsher 			break ;
25633f810b2SJeff Kirsher 		}
25733f810b2SJeff Kirsher 		/*RM22a*/
25833f810b2SJeff Kirsher 		else if (cmd == RM_ENABLE_FLAG) {
25933f810b2SJeff Kirsher 			if (smc->mib.m[MAC0].fddiMACMA_UnitdataEnable)
26033f810b2SJeff Kirsher 			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = TRUE ;
26133f810b2SJeff Kirsher 				else
26233f810b2SJeff Kirsher 			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
26333f810b2SJeff Kirsher 		}
26433f810b2SJeff Kirsher 		/*RM25*/
26533f810b2SJeff Kirsher 		else if (smc->r.dup_addr_test == DA_FAILED) {
26633f810b2SJeff Kirsher 			smc->mib.m[MAC0].fddiMACMA_UnitdataAvailable = FALSE ;
26733f810b2SJeff Kirsher 			smc->r.loop_avail = FALSE ;
26833f810b2SJeff Kirsher 			smc->r.da_flag = TRUE ;
26933f810b2SJeff Kirsher 			GO_STATE(RM5_RING_OP_DUP) ;
27033f810b2SJeff Kirsher 			break ;
27133f810b2SJeff Kirsher 		}
27233f810b2SJeff Kirsher 		break ;
27333f810b2SJeff Kirsher 	case ACTIONS(RM3_DETECT) :
27433f810b2SJeff Kirsher 		start_rmt_timer0(smc,smc->s.mac_d_max*2,RM_TIMEOUT_D_MAX) ;
27533f810b2SJeff Kirsher 		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
27633f810b2SJeff Kirsher 		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
27733f810b2SJeff Kirsher 		sm_mac_check_beacon_claim(smc) ;
2785671e8c1SJoe Perches 		DB_RMTN(1, "RMT : RM3_DETECT");
27933f810b2SJeff Kirsher 		ACTIONS_DONE() ;
28033f810b2SJeff Kirsher 		break ;
28133f810b2SJeff Kirsher 	case RM3_DETECT :
28233f810b2SJeff Kirsher 		if (cmd == RM_TIMEOUT_POLL) {
28333f810b2SJeff Kirsher 			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
28433f810b2SJeff Kirsher 			sm_mac_check_beacon_claim(smc) ;
28533f810b2SJeff Kirsher 			break ;
28633f810b2SJeff Kirsher 		}
28733f810b2SJeff Kirsher 		if (cmd == RM_TIMEOUT_D_MAX) {
28833f810b2SJeff Kirsher 			smc->r.timer0_exp = TRUE ;
28933f810b2SJeff Kirsher 		}
29033f810b2SJeff Kirsher 		/*
29133f810b2SJeff Kirsher 		 *jd(22-Feb-1999)
29233f810b2SJeff Kirsher 		 * We need a time ">= 2*mac_d_max" since we had finished
29333f810b2SJeff Kirsher 		 * Claim or Beacon state. So we will restart timer0 at
29433f810b2SJeff Kirsher 		 * every state change.
29533f810b2SJeff Kirsher 		 */
29633f810b2SJeff Kirsher 		if (cmd == RM_TX_STATE_CHANGE) {
29733f810b2SJeff Kirsher 			start_rmt_timer0(smc,
29833f810b2SJeff Kirsher 					 smc->s.mac_d_max*2,
29933f810b2SJeff Kirsher 					 RM_TIMEOUT_D_MAX) ;
30033f810b2SJeff Kirsher 		}
30133f810b2SJeff Kirsher 		/*RM32*/
30233f810b2SJeff Kirsher 		if (cmd == RM_RING_OP) {
30333f810b2SJeff Kirsher 			GO_STATE(RM2_RING_OP) ;
30433f810b2SJeff Kirsher 			break ;
30533f810b2SJeff Kirsher 		}
30633f810b2SJeff Kirsher 		/*RM33a*/
30733f810b2SJeff Kirsher 		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON)
30833f810b2SJeff Kirsher 			&& smc->r.bn_flag) {
30933f810b2SJeff Kirsher 			smc->r.bn_flag = FALSE ;
31033f810b2SJeff Kirsher 		}
31133f810b2SJeff Kirsher 		/*RM33b*/
31233f810b2SJeff Kirsher 		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
31333f810b2SJeff Kirsher 			int	tx ;
31433f810b2SJeff Kirsher 			/*
31533f810b2SJeff Kirsher 			 * set bn_flag only if in state T4 or T5:
31633f810b2SJeff Kirsher 			 * only if we're the beaconer should we start the
31733f810b2SJeff Kirsher 			 * trace !
31833f810b2SJeff Kirsher 			 */
31933f810b2SJeff Kirsher 			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
3205671e8c1SJoe Perches 			DB_RMTN(2, "RMT : DETECT && TRT_EXPIRED && T4/T5");
32133f810b2SJeff Kirsher 				smc->r.bn_flag = TRUE ;
32233f810b2SJeff Kirsher 				/*
32333f810b2SJeff Kirsher 				 * If one of the upstream stations beaconed
32433f810b2SJeff Kirsher 				 * and the link to the upstream neighbor is
32533f810b2SJeff Kirsher 				 * lost we need to restart the stuck timer to
32633f810b2SJeff Kirsher 				 * check the "stuck beacon" condition.
32733f810b2SJeff Kirsher 				 */
32833f810b2SJeff Kirsher 				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
32933f810b2SJeff Kirsher 					RM_TIMEOUT_T_STUCK) ;
33033f810b2SJeff Kirsher 			}
33133f810b2SJeff Kirsher 			/*
33233f810b2SJeff Kirsher 			 * We do NOT need to clear smc->r.bn_flag in case of
33333f810b2SJeff Kirsher 			 * not being in state T4 or T5, because the flag
33433f810b2SJeff Kirsher 			 * must be cleared in order to get in this condition.
33533f810b2SJeff Kirsher 			 */
33633f810b2SJeff Kirsher 
3375671e8c1SJoe Perches 			DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",
33833f810b2SJeff Kirsher 				tx, smc->r.bn_flag);
33933f810b2SJeff Kirsher 		}
34033f810b2SJeff Kirsher 		/*RM34a*/
34133f810b2SJeff Kirsher 		else if (cmd == RM_MY_CLAIM && smc->r.timer0_exp) {
34233f810b2SJeff Kirsher 			rmt_new_dup_actions(smc) ;
34333f810b2SJeff Kirsher 			GO_STATE(RM4_NON_OP_DUP) ;
34433f810b2SJeff Kirsher 			break ;
34533f810b2SJeff Kirsher 		}
34633f810b2SJeff Kirsher 		/*RM34b*/
34733f810b2SJeff Kirsher 		else if (cmd == RM_MY_BEACON && smc->r.timer0_exp) {
34833f810b2SJeff Kirsher 			rmt_new_dup_actions(smc) ;
34933f810b2SJeff Kirsher 			GO_STATE(RM4_NON_OP_DUP) ;
35033f810b2SJeff Kirsher 			break ;
35133f810b2SJeff Kirsher 		}
35233f810b2SJeff Kirsher 		/*RM34c*/
35333f810b2SJeff Kirsher 		else if (cmd == RM_VALID_CLAIM) {
35433f810b2SJeff Kirsher 			rmt_new_dup_actions(smc) ;
35533f810b2SJeff Kirsher 			GO_STATE(RM4_NON_OP_DUP) ;
35633f810b2SJeff Kirsher 			break ;
35733f810b2SJeff Kirsher 		}
35833f810b2SJeff Kirsher 		/*RM36*/
35933f810b2SJeff Kirsher 		else if (cmd == RM_TIMEOUT_T_STUCK &&
36033f810b2SJeff Kirsher 			smc->r.rm_join && smc->r.bn_flag) {
36133f810b2SJeff Kirsher 			GO_STATE(RM6_DIRECTED) ;
36233f810b2SJeff Kirsher 			break ;
36333f810b2SJeff Kirsher 		}
36433f810b2SJeff Kirsher 		break ;
36533f810b2SJeff Kirsher 	case ACTIONS(RM4_NON_OP_DUP) :
36633f810b2SJeff Kirsher 		start_rmt_timer0(smc,smc->s.rmt_t_announce,RM_TIMEOUT_ANNOUNCE);
36733f810b2SJeff Kirsher 		start_rmt_timer1(smc,smc->s.rmt_t_stuck,RM_TIMEOUT_T_STUCK) ;
36833f810b2SJeff Kirsher 		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
36933f810b2SJeff Kirsher 		sm_mac_check_beacon_claim(smc) ;
3705671e8c1SJoe Perches 		DB_RMTN(1, "RMT : RM4_NON_OP_DUP");
37133f810b2SJeff Kirsher 		ACTIONS_DONE() ;
37233f810b2SJeff Kirsher 		break ;
37333f810b2SJeff Kirsher 	case RM4_NON_OP_DUP :
37433f810b2SJeff Kirsher 		if (cmd == RM_TIMEOUT_POLL) {
37533f810b2SJeff Kirsher 			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
37633f810b2SJeff Kirsher 			sm_mac_check_beacon_claim(smc) ;
37733f810b2SJeff Kirsher 			break ;
37833f810b2SJeff Kirsher 		}
37933f810b2SJeff Kirsher 		/*RM41*/
38033f810b2SJeff Kirsher 		if (!smc->r.da_flag) {
38133f810b2SJeff Kirsher 			GO_STATE(RM1_NON_OP) ;
38233f810b2SJeff Kirsher 			break ;
38333f810b2SJeff Kirsher 		}
38433f810b2SJeff Kirsher 		/*RM44a*/
38533f810b2SJeff Kirsher 		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
38633f810b2SJeff Kirsher 			smc->r.bn_flag) {
38733f810b2SJeff Kirsher 			smc->r.bn_flag = FALSE ;
38833f810b2SJeff Kirsher 		}
38933f810b2SJeff Kirsher 		/*RM44b*/
39033f810b2SJeff Kirsher 		else if (cmd == RM_TRT_EXP && !smc->r.bn_flag) {
39133f810b2SJeff Kirsher 			int	tx ;
39233f810b2SJeff Kirsher 			/*
39333f810b2SJeff Kirsher 			 * set bn_flag only if in state T4 or T5:
39433f810b2SJeff Kirsher 			 * only if we're the beaconer should we start the
39533f810b2SJeff Kirsher 			 * trace !
39633f810b2SJeff Kirsher 			 */
39733f810b2SJeff Kirsher 			if ((tx =  sm_mac_get_tx_state(smc)) == 4 || tx == 5) {
3985671e8c1SJoe Perches 			DB_RMTN(2, "RMT : NOPDUP && TRT_EXPIRED && T4/T5");
39933f810b2SJeff Kirsher 				smc->r.bn_flag = TRUE ;
40033f810b2SJeff Kirsher 				/*
40133f810b2SJeff Kirsher 				 * If one of the upstream stations beaconed
40233f810b2SJeff Kirsher 				 * and the link to the upstream neighbor is
40333f810b2SJeff Kirsher 				 * lost we need to restart the stuck timer to
40433f810b2SJeff Kirsher 				 * check the "stuck beacon" condition.
40533f810b2SJeff Kirsher 				 */
40633f810b2SJeff Kirsher 				start_rmt_timer1(smc,smc->s.rmt_t_stuck,
40733f810b2SJeff Kirsher 					RM_TIMEOUT_T_STUCK) ;
40833f810b2SJeff Kirsher 			}
40933f810b2SJeff Kirsher 			/*
41033f810b2SJeff Kirsher 			 * We do NOT need to clear smc->r.bn_flag in case of
41133f810b2SJeff Kirsher 			 * not being in state T4 or T5, because the flag
41233f810b2SJeff Kirsher 			 * must be cleared in order to get in this condition.
41333f810b2SJeff Kirsher 			 */
41433f810b2SJeff Kirsher 
4155671e8c1SJoe Perches 			DB_RMTN(2, "RMT : sm_mac_get_tx_state() = %d (bn_flag = %d)",
41633f810b2SJeff Kirsher 				tx, smc->r.bn_flag);
41733f810b2SJeff Kirsher 		}
41833f810b2SJeff Kirsher 		/*RM44c*/
41933f810b2SJeff Kirsher 		else if (cmd == RM_TIMEOUT_ANNOUNCE && !smc->r.bn_flag) {
42033f810b2SJeff Kirsher 			rmt_dup_actions(smc) ;
42133f810b2SJeff Kirsher 		}
42233f810b2SJeff Kirsher 		/*RM45*/
42333f810b2SJeff Kirsher 		else if (cmd == RM_RING_OP) {
42433f810b2SJeff Kirsher 			smc->r.no_flag = FALSE ;
42533f810b2SJeff Kirsher 			GO_STATE(RM5_RING_OP_DUP) ;
42633f810b2SJeff Kirsher 			break ;
42733f810b2SJeff Kirsher 		}
42833f810b2SJeff Kirsher 		/*RM46*/
42933f810b2SJeff Kirsher 		else if (cmd == RM_TIMEOUT_T_STUCK &&
43033f810b2SJeff Kirsher 			smc->r.rm_join && smc->r.bn_flag) {
43133f810b2SJeff Kirsher 			GO_STATE(RM6_DIRECTED) ;
43233f810b2SJeff Kirsher 			break ;
43333f810b2SJeff Kirsher 		}
43433f810b2SJeff Kirsher 		break ;
43533f810b2SJeff Kirsher 	case ACTIONS(RM5_RING_OP_DUP) :
43633f810b2SJeff Kirsher 		stop_rmt_timer0(smc) ;
43733f810b2SJeff Kirsher 		stop_rmt_timer1(smc) ;
43833f810b2SJeff Kirsher 		stop_rmt_timer2(smc) ;
4395671e8c1SJoe Perches 		DB_RMTN(1, "RMT : RM5_RING_OP_DUP");
44033f810b2SJeff Kirsher 		ACTIONS_DONE() ;
44133f810b2SJeff Kirsher 		break;
44233f810b2SJeff Kirsher 	case RM5_RING_OP_DUP :
44333f810b2SJeff Kirsher 		/*RM52*/
44433f810b2SJeff Kirsher 		if (smc->r.dup_addr_test == DA_PASSED) {
44533f810b2SJeff Kirsher 			smc->r.da_flag = FALSE ;
44633f810b2SJeff Kirsher 			GO_STATE(RM2_RING_OP) ;
44733f810b2SJeff Kirsher 			break ;
44833f810b2SJeff Kirsher 		}
44933f810b2SJeff Kirsher 		/*RM54*/
45033f810b2SJeff Kirsher 		else if (cmd == RM_RING_NON_OP) {
45133f810b2SJeff Kirsher 			smc->r.jm_flag = FALSE ;
45233f810b2SJeff Kirsher 			smc->r.bn_flag = FALSE ;
45333f810b2SJeff Kirsher 			GO_STATE(RM4_NON_OP_DUP) ;
45433f810b2SJeff Kirsher 			break ;
45533f810b2SJeff Kirsher 		}
45633f810b2SJeff Kirsher 		break ;
45733f810b2SJeff Kirsher 	case ACTIONS(RM6_DIRECTED) :
45833f810b2SJeff Kirsher 		start_rmt_timer0(smc,smc->s.rmt_t_direct,RM_TIMEOUT_T_DIRECT) ;
45933f810b2SJeff Kirsher 		stop_rmt_timer1(smc) ;
46033f810b2SJeff Kirsher 		start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL) ;
46133f810b2SJeff Kirsher 		sm_ma_control(smc,MA_DIRECTED) ;
46233f810b2SJeff Kirsher 		RS_SET(smc,RS_BEACON) ;
4635671e8c1SJoe Perches 		DB_RMTN(1, "RMT : RM6_DIRECTED");
46433f810b2SJeff Kirsher 		ACTIONS_DONE() ;
46533f810b2SJeff Kirsher 		break ;
46633f810b2SJeff Kirsher 	case RM6_DIRECTED :
46733f810b2SJeff Kirsher 		/*RM63*/
46833f810b2SJeff Kirsher 		if (cmd == RM_TIMEOUT_POLL) {
46933f810b2SJeff Kirsher 			start_rmt_timer2(smc,smc->s.rmt_t_poll,RM_TIMEOUT_POLL);
47033f810b2SJeff Kirsher 			sm_mac_check_beacon_claim(smc) ;
47133f810b2SJeff Kirsher #ifndef SUPERNET_3
47233f810b2SJeff Kirsher 			/* Because of problems with the Supernet II chip set
47333f810b2SJeff Kirsher 			 * sending of Directed Beacon will stop after 165ms
47433f810b2SJeff Kirsher 			 * therefore restart_trt_for_dbcn(smc) will be called
47533f810b2SJeff Kirsher 			 * to prevent this.
47633f810b2SJeff Kirsher 			 */
47733f810b2SJeff Kirsher 			restart_trt_for_dbcn(smc) ;
47833f810b2SJeff Kirsher #endif /*SUPERNET_3*/
47933f810b2SJeff Kirsher 			break ;
48033f810b2SJeff Kirsher 		}
48133f810b2SJeff Kirsher 		if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
48233f810b2SJeff Kirsher 			!smc->r.da_flag) {
48333f810b2SJeff Kirsher 			smc->r.bn_flag = FALSE ;
48433f810b2SJeff Kirsher 			GO_STATE(RM3_DETECT) ;
48533f810b2SJeff Kirsher 			break ;
48633f810b2SJeff Kirsher 		}
48733f810b2SJeff Kirsher 		/*RM64*/
48833f810b2SJeff Kirsher 		else if ((cmd == RM_MY_BEACON || cmd == RM_OTHER_BEACON) &&
48933f810b2SJeff Kirsher 			smc->r.da_flag) {
49033f810b2SJeff Kirsher 			smc->r.bn_flag = FALSE ;
49133f810b2SJeff Kirsher 			GO_STATE(RM4_NON_OP_DUP) ;
49233f810b2SJeff Kirsher 			break ;
49333f810b2SJeff Kirsher 		}
49433f810b2SJeff Kirsher 		/*RM67*/
49533f810b2SJeff Kirsher 		else if (cmd == RM_TIMEOUT_T_DIRECT) {
49633f810b2SJeff Kirsher 			GO_STATE(RM7_TRACE) ;
49733f810b2SJeff Kirsher 			break ;
49833f810b2SJeff Kirsher 		}
49933f810b2SJeff Kirsher 		break ;
50033f810b2SJeff Kirsher 	case ACTIONS(RM7_TRACE) :
50133f810b2SJeff Kirsher 		stop_rmt_timer0(smc) ;
50233f810b2SJeff Kirsher 		stop_rmt_timer1(smc) ;
50333f810b2SJeff Kirsher 		stop_rmt_timer2(smc) ;
50433f810b2SJeff Kirsher 		smc->e.trace_prop |= ENTITY_BIT(ENTITY_MAC) ;
50533f810b2SJeff Kirsher 		queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ;
5065671e8c1SJoe Perches 		DB_RMTN(1, "RMT : RM7_TRACE");
50733f810b2SJeff Kirsher 		ACTIONS_DONE() ;
50833f810b2SJeff Kirsher 		break ;
50933f810b2SJeff Kirsher 	case RM7_TRACE :
51033f810b2SJeff Kirsher 		break ;
51133f810b2SJeff Kirsher 	default:
51233f810b2SJeff Kirsher 		SMT_PANIC(smc,SMT_E0122, SMT_E0122_MSG) ;
51333f810b2SJeff Kirsher 		break;
51433f810b2SJeff Kirsher 	}
51533f810b2SJeff Kirsher }
51633f810b2SJeff Kirsher 
51733f810b2SJeff Kirsher /*
51833f810b2SJeff Kirsher  * (jd) RMT duplicate address actions
51933f810b2SJeff Kirsher  * leave the ring or reinsert just as configured
52033f810b2SJeff Kirsher  */
rmt_dup_actions(struct s_smc * smc)52133f810b2SJeff Kirsher static void rmt_dup_actions(struct s_smc *smc)
52233f810b2SJeff Kirsher {
52333f810b2SJeff Kirsher 	if (smc->r.jm_flag) {
52433f810b2SJeff Kirsher 	}
52533f810b2SJeff Kirsher 	else {
52633f810b2SJeff Kirsher 		if (smc->s.rmt_dup_mac_behavior) {
52733f810b2SJeff Kirsher 			SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
52833f810b2SJeff Kirsher                         rmt_reinsert_actions(smc) ;
52933f810b2SJeff Kirsher 		}
53033f810b2SJeff Kirsher 		else {
53133f810b2SJeff Kirsher 			SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
53233f810b2SJeff Kirsher 			rmt_leave_actions(smc) ;
53333f810b2SJeff Kirsher 		}
53433f810b2SJeff Kirsher 	}
53533f810b2SJeff Kirsher }
53633f810b2SJeff Kirsher 
53733f810b2SJeff Kirsher /*
53833f810b2SJeff Kirsher  * Reconnect to the Ring
53933f810b2SJeff Kirsher  */
rmt_reinsert_actions(struct s_smc * smc)54033f810b2SJeff Kirsher static void rmt_reinsert_actions(struct s_smc *smc)
54133f810b2SJeff Kirsher {
54233f810b2SJeff Kirsher 	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
54333f810b2SJeff Kirsher 	queue_event(smc,EVENT_ECM,EC_CONNECT) ;
54433f810b2SJeff Kirsher }
54533f810b2SJeff Kirsher 
54633f810b2SJeff Kirsher /*
54733f810b2SJeff Kirsher  * duplicate address detected
54833f810b2SJeff Kirsher  */
rmt_new_dup_actions(struct s_smc * smc)54933f810b2SJeff Kirsher static void rmt_new_dup_actions(struct s_smc *smc)
55033f810b2SJeff Kirsher {
55133f810b2SJeff Kirsher 	smc->r.da_flag = TRUE ;
55233f810b2SJeff Kirsher 	smc->r.bn_flag = FALSE ;
55333f810b2SJeff Kirsher 	smc->r.jm_flag = FALSE ;
55433f810b2SJeff Kirsher 	/*
55533f810b2SJeff Kirsher 	 * we have three options : change address, jam or leave
55633f810b2SJeff Kirsher 	 * we leave the ring as default
55733f810b2SJeff Kirsher 	 * Optionally it's possible to reinsert after leaving the Ring
55833f810b2SJeff Kirsher 	 * but this will not conform with SMT Spec.
55933f810b2SJeff Kirsher 	 */
56033f810b2SJeff Kirsher 	if (smc->s.rmt_dup_mac_behavior) {
56133f810b2SJeff Kirsher 		SMT_ERR_LOG(smc,SMT_E0138, SMT_E0138_MSG) ;
56233f810b2SJeff Kirsher 		rmt_reinsert_actions(smc) ;
56333f810b2SJeff Kirsher 	}
56433f810b2SJeff Kirsher 	else {
56533f810b2SJeff Kirsher 		SMT_ERR_LOG(smc,SMT_E0135, SMT_E0135_MSG) ;
56633f810b2SJeff Kirsher 		rmt_leave_actions(smc) ;
56733f810b2SJeff Kirsher 	}
56833f810b2SJeff Kirsher }
56933f810b2SJeff Kirsher 
57033f810b2SJeff Kirsher 
57133f810b2SJeff Kirsher /*
57233f810b2SJeff Kirsher  * leave the ring
57333f810b2SJeff Kirsher  */
rmt_leave_actions(struct s_smc * smc)57433f810b2SJeff Kirsher static void rmt_leave_actions(struct s_smc *smc)
57533f810b2SJeff Kirsher {
57633f810b2SJeff Kirsher 	queue_event(smc,EVENT_ECM,EC_DISCONNECT) ;
57733f810b2SJeff Kirsher 	/*
57833f810b2SJeff Kirsher 	 * Note: Do NOT try again later. (with please reconnect)
57933f810b2SJeff Kirsher 	 * The station must be left from the ring!
58033f810b2SJeff Kirsher 	 */
58133f810b2SJeff Kirsher }
58233f810b2SJeff Kirsher 
58333f810b2SJeff Kirsher /*
58433f810b2SJeff Kirsher  * SMT timer interface
58533f810b2SJeff Kirsher  *	start RMT timer 0
58633f810b2SJeff Kirsher  */
start_rmt_timer0(struct s_smc * smc,u_long value,int event)58733f810b2SJeff Kirsher static void start_rmt_timer0(struct s_smc *smc, u_long value, int event)
58833f810b2SJeff Kirsher {
58933f810b2SJeff Kirsher 	smc->r.timer0_exp = FALSE ;		/* clear timer event flag */
59033f810b2SJeff Kirsher 	smt_timer_start(smc,&smc->r.rmt_timer0,value,EV_TOKEN(EVENT_RMT,event));
59133f810b2SJeff Kirsher }
59233f810b2SJeff Kirsher 
59333f810b2SJeff Kirsher /*
59433f810b2SJeff Kirsher  * SMT timer interface
59533f810b2SJeff Kirsher  *	start RMT timer 1
59633f810b2SJeff Kirsher  */
start_rmt_timer1(struct s_smc * smc,u_long value,int event)59733f810b2SJeff Kirsher static void start_rmt_timer1(struct s_smc *smc, u_long value, int event)
59833f810b2SJeff Kirsher {
59933f810b2SJeff Kirsher 	smc->r.timer1_exp = FALSE ;	/* clear timer event flag */
60033f810b2SJeff Kirsher 	smt_timer_start(smc,&smc->r.rmt_timer1,value,EV_TOKEN(EVENT_RMT,event));
60133f810b2SJeff Kirsher }
60233f810b2SJeff Kirsher 
60333f810b2SJeff Kirsher /*
60433f810b2SJeff Kirsher  * SMT timer interface
60533f810b2SJeff Kirsher  *	start RMT timer 2
60633f810b2SJeff Kirsher  */
start_rmt_timer2(struct s_smc * smc,u_long value,int event)60733f810b2SJeff Kirsher static void start_rmt_timer2(struct s_smc *smc, u_long value, int event)
60833f810b2SJeff Kirsher {
60933f810b2SJeff Kirsher 	smc->r.timer2_exp = FALSE ;		/* clear timer event flag */
61033f810b2SJeff Kirsher 	smt_timer_start(smc,&smc->r.rmt_timer2,value,EV_TOKEN(EVENT_RMT,event));
61133f810b2SJeff Kirsher }
61233f810b2SJeff Kirsher 
61333f810b2SJeff Kirsher /*
61433f810b2SJeff Kirsher  * SMT timer interface
61533f810b2SJeff Kirsher  *	stop RMT timer 0
61633f810b2SJeff Kirsher  */
stop_rmt_timer0(struct s_smc * smc)61733f810b2SJeff Kirsher static void stop_rmt_timer0(struct s_smc *smc)
61833f810b2SJeff Kirsher {
61933f810b2SJeff Kirsher 	if (smc->r.rmt_timer0.tm_active)
62033f810b2SJeff Kirsher 		smt_timer_stop(smc,&smc->r.rmt_timer0) ;
62133f810b2SJeff Kirsher }
62233f810b2SJeff Kirsher 
62333f810b2SJeff Kirsher /*
62433f810b2SJeff Kirsher  * SMT timer interface
62533f810b2SJeff Kirsher  *	stop RMT timer 1
62633f810b2SJeff Kirsher  */
stop_rmt_timer1(struct s_smc * smc)62733f810b2SJeff Kirsher static void stop_rmt_timer1(struct s_smc *smc)
62833f810b2SJeff Kirsher {
62933f810b2SJeff Kirsher 	if (smc->r.rmt_timer1.tm_active)
63033f810b2SJeff Kirsher 		smt_timer_stop(smc,&smc->r.rmt_timer1) ;
63133f810b2SJeff Kirsher }
63233f810b2SJeff Kirsher 
63333f810b2SJeff Kirsher /*
63433f810b2SJeff Kirsher  * SMT timer interface
63533f810b2SJeff Kirsher  *	stop RMT timer 2
63633f810b2SJeff Kirsher  */
stop_rmt_timer2(struct s_smc * smc)63733f810b2SJeff Kirsher static void stop_rmt_timer2(struct s_smc *smc)
63833f810b2SJeff Kirsher {
63933f810b2SJeff Kirsher 	if (smc->r.rmt_timer2.tm_active)
64033f810b2SJeff Kirsher 		smt_timer_stop(smc,&smc->r.rmt_timer2) ;
64133f810b2SJeff Kirsher }
64233f810b2SJeff Kirsher 
643