cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ecm.c (12438B)


      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 ECM
     15	Entity Coordination Management
     16	Hardware independent state machine
     17*/
     18
     19/*
     20 * Hardware independent state machine implemantation
     21 * The following external SMT functions are referenced :
     22 *
     23 * 		queue_event()
     24 * 		smt_timer_start()
     25 * 		smt_timer_stop()
     26 *
     27 * 	The following external HW dependent functions are referenced :
     28 * 		sm_pm_bypass_req()
     29 * 		sm_pm_get_ls()
     30 * 
     31 * 	The following HW dependent events are required :
     32 *		NONE
     33 *
     34 */
     35
     36#include "h/types.h"
     37#include "h/fddi.h"
     38#include "h/smc.h"
     39
     40#define KERNEL
     41#include "h/smtstate.h"
     42
     43/*
     44 * FSM Macros
     45 */
     46#define AFLAG	0x10
     47#define GO_STATE(x)	(smc->mib.fddiSMTECMState = (x)|AFLAG)
     48#define ACTIONS_DONE()	(smc->mib.fddiSMTECMState &= ~AFLAG)
     49#define ACTIONS(x)	(x|AFLAG)
     50
     51#define EC0_OUT		0			/* not inserted */
     52#define EC1_IN		1			/* inserted */
     53#define EC2_TRACE	2			/* tracing */
     54#define EC3_LEAVE	3			/* leaving the ring */
     55#define EC4_PATH_TEST	4			/* performing path test */
     56#define EC5_INSERT	5			/* bypass being turned on */
     57#define EC6_CHECK	6			/* checking bypass */
     58#define EC7_DEINSERT	7			/* bypass being turnde off */
     59
     60/*
     61 * symbolic state names
     62 */
     63static const char * const ecm_states[] = {
     64	"EC0_OUT","EC1_IN","EC2_TRACE","EC3_LEAVE","EC4_PATH_TEST",
     65	"EC5_INSERT","EC6_CHECK","EC7_DEINSERT"
     66} ;
     67
     68/*
     69 * symbolic event names
     70 */
     71static const char * const ecm_events[] = {
     72	"NONE","EC_CONNECT","EC_DISCONNECT","EC_TRACE_PROP","EC_PATH_TEST",
     73	"EC_TIMEOUT_TD","EC_TIMEOUT_TMAX",
     74	"EC_TIMEOUT_IMAX","EC_TIMEOUT_INMAX","EC_TEST_DONE"
     75} ;
     76
     77/*
     78 * all Globals  are defined in smc.h
     79 * struct s_ecm
     80 */
     81
     82/*
     83 * function declarations
     84 */
     85
     86static void ecm_fsm(struct s_smc *smc, int cmd);
     87static void start_ecm_timer(struct s_smc *smc, u_long value, int event);
     88static void stop_ecm_timer(struct s_smc *smc);
     89static void prop_actions(struct s_smc *smc);
     90
     91/*
     92	init ECM state machine
     93	clear all ECM vars and flags
     94*/
     95void ecm_init(struct s_smc *smc)
     96{
     97	smc->e.path_test = PT_PASSED ;
     98	smc->e.trace_prop = 0 ;
     99	smc->e.sb_flag = 0 ;
    100	smc->mib.fddiSMTECMState = ACTIONS(EC0_OUT) ;
    101	smc->e.ecm_line_state = FALSE ;
    102}
    103
    104/*
    105	ECM state machine
    106	called by dispatcher
    107
    108	do
    109		display state change
    110		process event
    111	until SM is stable
    112*/
    113void ecm(struct s_smc *smc, int event)
    114{
    115	int	state ;
    116
    117	do {
    118		DB_ECM("ECM : state %s%s event %s",
    119		       smc->mib.fddiSMTECMState & AFLAG ? "ACTIONS " : "",
    120		       ecm_states[smc->mib.fddiSMTECMState & ~AFLAG],
    121		       ecm_events[event]);
    122		state = smc->mib.fddiSMTECMState ;
    123		ecm_fsm(smc,event) ;
    124		event = 0 ;
    125	} while (state != smc->mib.fddiSMTECMState) ;
    126	ecm_state_change(smc,(int)smc->mib.fddiSMTECMState) ;
    127}
    128
    129/*
    130	process ECM event
    131*/
    132static void ecm_fsm(struct s_smc *smc, int cmd)
    133{
    134	int ls_a ;			/* current line state PHY A */
    135	int ls_b ;			/* current line state PHY B */
    136	int	p ;			/* ports */
    137
    138
    139	smc->mib.fddiSMTBypassPresent = sm_pm_bypass_present(smc) ;
    140	if (cmd == EC_CONNECT)
    141		smc->mib.fddiSMTRemoteDisconnectFlag = FALSE ;
    142
    143	/* For AIX event notification: */
    144	/* Is a disconnect  command remotely issued ? */
    145	if (cmd == EC_DISCONNECT &&
    146	    smc->mib.fddiSMTRemoteDisconnectFlag == TRUE) {
    147		AIX_EVENT (smc, (u_long) CIO_HARD_FAIL, (u_long)
    148			FDDI_REMOTE_DISCONNECT, smt_get_event_word(smc),
    149			smt_get_error_word(smc) );
    150	}
    151
    152	/*jd 05-Aug-1999 Bug #10419 "Port Disconnect fails at Dup MAc Cond."*/
    153	if (cmd == EC_CONNECT) {
    154		smc->e.DisconnectFlag = FALSE ;
    155	}
    156	else if (cmd == EC_DISCONNECT) {
    157		smc->e.DisconnectFlag = TRUE ;
    158	}
    159	
    160	switch(smc->mib.fddiSMTECMState) {
    161	case ACTIONS(EC0_OUT) :
    162		/*
    163		 * We do not perform a path test
    164		 */
    165		smc->e.path_test = PT_PASSED ;
    166		smc->e.ecm_line_state = FALSE ;
    167		stop_ecm_timer(smc) ;
    168		ACTIONS_DONE() ;
    169		break ;
    170	case EC0_OUT:
    171		/*EC01*/
    172		if (cmd == EC_CONNECT && !smc->mib.fddiSMTBypassPresent
    173			&& smc->e.path_test==PT_PASSED) {
    174			GO_STATE(EC1_IN) ;
    175			break ;
    176		}
    177		/*EC05*/
    178		else if (cmd == EC_CONNECT && (smc->e.path_test==PT_PASSED) &&
    179			smc->mib.fddiSMTBypassPresent &&
    180			(smc->s.sas == SMT_DAS)) {
    181			GO_STATE(EC5_INSERT) ;
    182			break ;
    183		}
    184		break;
    185	case ACTIONS(EC1_IN) :
    186		stop_ecm_timer(smc) ;
    187		smc->e.trace_prop = 0 ;
    188		sm_ma_control(smc,MA_TREQ) ;
    189		for (p = 0 ; p < NUMPHYS ; p++)
    190			if (smc->mib.p[p].fddiPORTHardwarePresent)
    191				queue_event(smc,EVENT_PCMA+p,PC_START) ;
    192		ACTIONS_DONE() ;
    193		break ;
    194	case EC1_IN:
    195		/*EC12*/
    196		if (cmd == EC_TRACE_PROP) {
    197			prop_actions(smc) ;
    198			GO_STATE(EC2_TRACE) ;
    199			break ;
    200		}
    201		/*EC13*/
    202		else if (cmd == EC_DISCONNECT) {
    203			GO_STATE(EC3_LEAVE) ;
    204			break ;
    205		}
    206		break;
    207	case ACTIONS(EC2_TRACE) :
    208		start_ecm_timer(smc,MIB2US(smc->mib.fddiSMTTrace_MaxExpiration),
    209			EC_TIMEOUT_TMAX) ;
    210		ACTIONS_DONE() ;
    211		break ;
    212	case EC2_TRACE :
    213		/*EC22*/
    214		if (cmd == EC_TRACE_PROP) {
    215			prop_actions(smc) ;
    216			GO_STATE(EC2_TRACE) ;
    217			break ;
    218		}
    219		/*EC23a*/
    220		else if (cmd == EC_DISCONNECT) {
    221			smc->e.path_test = PT_EXITING ;
    222			GO_STATE(EC3_LEAVE) ;
    223			break ;
    224		}
    225		/*EC23b*/
    226		else if (smc->e.path_test == PT_PENDING) {
    227			GO_STATE(EC3_LEAVE) ;
    228			break ;
    229		}
    230		/*EC23c*/
    231		else if (cmd == EC_TIMEOUT_TMAX) {
    232			/* Trace_Max is expired */
    233			/* -> send AIX_EVENT */
    234			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS,
    235				(u_long) FDDI_SMT_ERROR, (u_long)
    236				FDDI_TRACE_MAX, smt_get_error_word(smc));
    237			smc->e.path_test = PT_PENDING ;
    238			GO_STATE(EC3_LEAVE) ;
    239			break ;
    240		}
    241		break ;
    242	case ACTIONS(EC3_LEAVE) :
    243		start_ecm_timer(smc,smc->s.ecm_td_min,EC_TIMEOUT_TD) ;
    244		for (p = 0 ; p < NUMPHYS ; p++)
    245			queue_event(smc,EVENT_PCMA+p,PC_STOP) ;
    246		ACTIONS_DONE() ;
    247		break ;
    248	case EC3_LEAVE:
    249		/*EC30*/
    250		if (cmd == EC_TIMEOUT_TD && !smc->mib.fddiSMTBypassPresent &&
    251			(smc->e.path_test != PT_PENDING)) {
    252			GO_STATE(EC0_OUT) ;
    253			break ;
    254		}
    255		/*EC34*/
    256		else if (cmd == EC_TIMEOUT_TD &&
    257			(smc->e.path_test == PT_PENDING)) {
    258			GO_STATE(EC4_PATH_TEST) ;
    259			break ;
    260		}
    261		/*EC31*/
    262		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
    263			GO_STATE(EC1_IN) ;
    264			break ;
    265		}
    266		/*EC33*/
    267		else if (cmd == EC_DISCONNECT &&
    268			smc->e.path_test == PT_PENDING) {
    269			smc->e.path_test = PT_EXITING ;
    270			/*
    271			 * stay in state - state will be left via timeout
    272			 */
    273		}
    274		/*EC37*/
    275		else if (cmd == EC_TIMEOUT_TD &&
    276			smc->mib.fddiSMTBypassPresent &&
    277			smc->e.path_test != PT_PENDING) {
    278			GO_STATE(EC7_DEINSERT) ;
    279			break ;
    280		}
    281		break ;
    282	case ACTIONS(EC4_PATH_TEST) :
    283		stop_ecm_timer(smc) ;
    284		smc->e.path_test = PT_TESTING ;
    285		start_ecm_timer(smc,smc->s.ecm_test_done,EC_TEST_DONE) ;
    286		/* now perform path test ... just a simulation */
    287		ACTIONS_DONE() ;
    288		break ;
    289	case EC4_PATH_TEST :
    290		/* path test done delay */
    291		if (cmd == EC_TEST_DONE)
    292			smc->e.path_test = PT_PASSED ;
    293
    294		if (smc->e.path_test == PT_FAILED)
    295			RS_SET(smc,RS_PATHTEST) ;
    296
    297		/*EC40a*/
    298		if (smc->e.path_test == PT_FAILED &&
    299			!smc->mib.fddiSMTBypassPresent) {
    300			GO_STATE(EC0_OUT) ;
    301			break ;
    302		}
    303		/*EC40b*/
    304		else if (cmd == EC_DISCONNECT &&
    305			!smc->mib.fddiSMTBypassPresent) {
    306			GO_STATE(EC0_OUT) ;
    307			break ;
    308		}
    309		/*EC41*/
    310		else if (smc->e.path_test == PT_PASSED) {
    311			GO_STATE(EC1_IN) ;
    312			break ;
    313		}
    314		/*EC47a*/
    315		else if (smc->e.path_test == PT_FAILED &&
    316			smc->mib.fddiSMTBypassPresent) {
    317			GO_STATE(EC7_DEINSERT) ;
    318			break ;
    319		}
    320		/*EC47b*/
    321		else if (cmd == EC_DISCONNECT &&
    322			smc->mib.fddiSMTBypassPresent) {
    323			GO_STATE(EC7_DEINSERT) ;
    324			break ;
    325		}
    326		break ;
    327	case ACTIONS(EC5_INSERT) :
    328		sm_pm_bypass_req(smc,BP_INSERT);
    329		start_ecm_timer(smc,smc->s.ecm_in_max,EC_TIMEOUT_INMAX) ;
    330		ACTIONS_DONE() ;
    331		break ;
    332	case EC5_INSERT :
    333		/*EC56*/
    334		if (cmd == EC_TIMEOUT_INMAX) {
    335			GO_STATE(EC6_CHECK) ;
    336			break ;
    337		}
    338		/*EC57*/
    339		else if (cmd == EC_DISCONNECT) {
    340			GO_STATE(EC7_DEINSERT) ;
    341			break ;
    342		}
    343		break ;
    344	case ACTIONS(EC6_CHECK) :
    345		/*
    346		 * in EC6_CHECK, we *POLL* the line state !
    347		 * check whether both bypass switches have switched.
    348		 */
    349		start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
    350		smc->e.ecm_line_state = TRUE ;	/* flag to pcm: report Q/HLS */
    351		ACTIONS_DONE() ;
    352		break ;
    353	case EC6_CHECK :
    354		ls_a = sm_pm_get_ls(smc,PA) ;
    355		ls_b = sm_pm_get_ls(smc,PB) ;
    356
    357		/*EC61*/
    358		if (((ls_a == PC_QLS) || (ls_a == PC_HLS)) &&
    359		    ((ls_b == PC_QLS) || (ls_b == PC_HLS)) ) {
    360			smc->e.sb_flag = FALSE ;
    361			smc->e.ecm_line_state = FALSE ;
    362			GO_STATE(EC1_IN) ;
    363			break ;
    364		}
    365		/*EC66*/
    366		else if (!smc->e.sb_flag &&
    367			 (((ls_a == PC_ILS) && (ls_b == PC_QLS)) ||
    368			  ((ls_a == PC_QLS) && (ls_b == PC_ILS)))){
    369			smc->e.sb_flag = TRUE ;
    370			DB_ECMN(1, "ECM : EC6_CHECK - stuck bypass");
    371			AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long)
    372				FDDI_SMT_ERROR, (u_long) FDDI_BYPASS_STUCK,
    373				smt_get_error_word(smc));
    374		}
    375		/*EC67*/
    376		else if (cmd == EC_DISCONNECT) {
    377			smc->e.ecm_line_state = FALSE ;
    378			GO_STATE(EC7_DEINSERT) ;
    379			break ;
    380		}
    381		else {
    382			/*
    383			 * restart poll
    384			 */
    385			start_ecm_timer(smc,smc->s.ecm_check_poll,0) ;
    386		}
    387		break ;
    388	case ACTIONS(EC7_DEINSERT) :
    389		sm_pm_bypass_req(smc,BP_DEINSERT);
    390		start_ecm_timer(smc,smc->s.ecm_i_max,EC_TIMEOUT_IMAX) ;
    391		ACTIONS_DONE() ;
    392		break ;
    393	case EC7_DEINSERT:
    394		/*EC70*/
    395		if (cmd == EC_TIMEOUT_IMAX) {
    396			GO_STATE(EC0_OUT) ;
    397			break ;
    398		}
    399		/*EC75*/
    400		else if (cmd == EC_CONNECT && smc->e.path_test == PT_PASSED) {
    401			GO_STATE(EC5_INSERT) ;
    402			break ;
    403		}
    404		break;
    405	default:
    406		SMT_PANIC(smc,SMT_E0107, SMT_E0107_MSG) ;
    407		break;
    408	}
    409}
    410
    411#ifndef	CONCENTRATOR
    412/*
    413 * trace propagation actions for SAS & DAS
    414 */
    415static void prop_actions(struct s_smc *smc)
    416{
    417	int	port_in = 0 ;
    418	int	port_out = 0 ;
    419
    420	RS_SET(smc,RS_EVENT) ;
    421	switch (smc->s.sas) {
    422	case SMT_SAS :
    423		port_in = port_out = pcm_get_s_port(smc) ;
    424		break ;
    425	case SMT_DAS :
    426		port_in = cfm_get_mac_input(smc) ;	/* PA or PB */
    427		port_out = cfm_get_mac_output(smc) ;	/* PA or PB */
    428		break ;
    429	case SMT_NAC :
    430		SMT_PANIC(smc,SMT_E0108, SMT_E0108_MSG) ;
    431		return ;
    432	}
    433
    434	DB_ECM("ECM : prop_actions - trace_prop %lu", smc->e.trace_prop);
    435	DB_ECM("ECM : prop_actions - in %d out %d", port_in, port_out);
    436
    437	if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
    438		/* trace initiatior */
    439		DB_ECM("ECM : initiate TRACE on PHY %c", 'A' + port_in - PA);
    440		queue_event(smc,EVENT_PCM+port_in,PC_TRACE) ;
    441	}
    442	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PA))) &&
    443		port_out != PA) {
    444		/* trace propagate upstream */
    445		DB_ECM("ECM : propagate TRACE on PHY B");
    446		queue_event(smc,EVENT_PCMB,PC_TRACE) ;
    447	}
    448	else if ((smc->e.trace_prop & ENTITY_BIT(ENTITY_PHY(PB))) &&
    449		port_out != PB) {
    450		/* trace propagate upstream */
    451		DB_ECM("ECM : propagate TRACE on PHY A");
    452		queue_event(smc,EVENT_PCMA,PC_TRACE) ;
    453	}
    454	else {
    455		/* signal trace termination */
    456		DB_ECM("ECM : TRACE terminated");
    457		smc->e.path_test = PT_PENDING ;
    458	}
    459	smc->e.trace_prop = 0 ;
    460}
    461#else
    462/*
    463 * trace propagation actions for Concentrator
    464 */
    465static void prop_actions(struct s_smc *smc)
    466{
    467	int	initiator ;
    468	int	upstream ;
    469	int	p ;
    470
    471	RS_SET(smc,RS_EVENT) ;
    472	while (smc->e.trace_prop) {
    473		DB_ECM("ECM : prop_actions - trace_prop %d",
    474		       smc->e.trace_prop);
    475
    476		if (smc->e.trace_prop & ENTITY_BIT(ENTITY_MAC)) {
    477			initiator = ENTITY_MAC ;
    478			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_MAC) ;
    479			DB_ECM("ECM: MAC initiates trace");
    480		}
    481		else {
    482			for (p = NUMPHYS-1 ; p >= 0 ; p--) {
    483				if (smc->e.trace_prop &
    484					ENTITY_BIT(ENTITY_PHY(p)))
    485					break ;
    486			}
    487			initiator = ENTITY_PHY(p) ;
    488			smc->e.trace_prop &= ~ENTITY_BIT(ENTITY_PHY(p)) ;
    489		}
    490		upstream = cem_get_upstream(smc,initiator) ;
    491
    492		if (upstream == ENTITY_MAC) {
    493			/* signal trace termination */
    494			DB_ECM("ECM : TRACE terminated");
    495			smc->e.path_test = PT_PENDING ;
    496		}
    497		else {
    498			/* trace propagate upstream */
    499			DB_ECM("ECM : propagate TRACE on PHY %d", upstream);
    500			queue_event(smc,EVENT_PCM+upstream,PC_TRACE) ;
    501		}
    502	}
    503}
    504#endif
    505
    506
    507/*
    508 * SMT timer interface
    509 *	start ECM timer
    510 */
    511static void start_ecm_timer(struct s_smc *smc, u_long value, int event)
    512{
    513	smt_timer_start(smc,&smc->e.ecm_timer,value,EV_TOKEN(EVENT_ECM,event));
    514}
    515
    516/*
    517 * SMT timer interface
    518 *	stop ECM timer
    519 */
    520static void stop_ecm_timer(struct s_smc *smc)
    521{
    522	if (smc->e.ecm_timer.tm_active)
    523		smt_timer_stop(smc,&smc->e.ecm_timer) ;
    524}