cregit-Linux how code gets into the kernel

Release 4.7 drivers/net/fddi/skfp/pcmplc.c

/******************************************************************************
 *
 *      (C)Copyright 1998,1999 SysKonnect,
 *      a business unit of Schneider & Koch & Co. Datensysteme GmbH.
 *
 *      See the file "skfddi.c" for further information.
 *
 *      This program is free software; you can redistribute it and/or modify
 *      it under the terms of the GNU General Public License as published by
 *      the Free Software Foundation; either version 2 of the License, or
 *      (at your option) any later version.
 *
 *      The information in this file is provided "AS IS" without warranty.
 *
 ******************************************************************************/

/*
        PCM
        Physical Connection Management
*/

/*
 * Hardware independent state machine implemantation
 * The following external SMT functions are referenced :
 *
 *              queue_event()
 *              smt_timer_start()
 *              smt_timer_stop()
 *
 *      The following external HW dependent functions are referenced :
 *              sm_pm_control()
 *              sm_ph_linestate()
 *              sm_pm_ls_latch()
 *
 *      The following HW dependent events are required :
 *              PC_QLS
 *              PC_ILS
 *              PC_HLS
 *              PC_MLS
 *              PC_NSE
 *              PC_LEM
 *
 */


#include "h/types.h"
#include "h/fddi.h"
#include "h/smc.h"
#include "h/supern_2.h"

#define KERNEL
#include "h/smtstate.h"

#ifndef	lint

static const char ID_sccs[] = "@(#)pcmplc.c   2.55 99/08/05 (C) SK " ;
#endif

#ifdef	FDDI_MIB
extern int snmp_fddi_trap(
#ifdef	ANSIC
struct s_smc	* smc, int  type, int  index
#endif
);
#endif
#ifdef	CONCENTRATOR
extern int plc_is_installed(
#ifdef	ANSIC
struct s_smc *smc ,
int p
#endif
) ;
#endif
/*
 * FSM Macros
 */

#define AFLAG		(0x20)

#define GO_STATE(x)	(mib->fddiPORTPCMState = (x)|AFLAG)

#define ACTIONS_DONE()	(mib->fddiPORTPCMState &= ~AFLAG)

#define ACTIONS(x)	(x|AFLAG)

/*
 * PCM states
 */

#define PC0_OFF			0

#define PC1_BREAK		1

#define PC2_TRACE		2

#define PC3_CONNECT		3

#define PC4_NEXT		4

#define PC5_SIGNAL		5

#define PC6_JOIN		6

#define PC7_VERIFY		7

#define PC8_ACTIVE		8

#define PC9_MAINT		9

#ifdef	DEBUG
/*
 * symbolic state names
 */

static const char * const pcm_states[] =  {
	"PC0_OFF","PC1_BREAK","PC2_TRACE","PC3_CONNECT","PC4_NEXT",
	"PC5_SIGNAL","PC6_JOIN","PC7_VERIFY","PC8_ACTIVE","PC9_MAINT"
} ;

/*
 * symbolic event names
 */

static const char * const pcm_events[] = {
	"NONE","PC_START","PC_STOP","PC_LOOP","PC_JOIN","PC_SIGNAL",
	"PC_REJECT","PC_MAINT","PC_TRACE","PC_PDR",
	"PC_ENABLE","PC_DISABLE",
	"PC_QLS","PC_ILS","PC_MLS","PC_HLS","PC_LS_PDR","PC_LS_NONE",
	"PC_TIMEOUT_TB_MAX","PC_TIMEOUT_TB_MIN",
	"PC_TIMEOUT_C_MIN","PC_TIMEOUT_T_OUT",
	"PC_TIMEOUT_TL_MIN","PC_TIMEOUT_T_NEXT","PC_TIMEOUT_LCT",
	"PC_NSE","PC_LEM"
} ;
#endif

#ifdef	MOT_ELM
/*
 * PCL-S control register
 * this register in the PLC-S controls the scrambling parameters
 */

#define PLCS_CONTROL_C_U	0

#define PLCS_CONTROL_C_S	(PL_C_SDOFF_ENABLE | PL_C_SDON_ENABLE | \
                                 PL_C_CIPHER_ENABLE)

#define	PLCS_FASSERT_U		0

#define	PLCS_FASSERT_S		0xFd76	
/* 52.0 us */

#define	PLCS_FDEASSERT_U	0

#define	PLCS_FDEASSERT_S	0
#else	/* nMOT_ELM */
/*
 * PCL-S control register
 * this register in the PLC-S controls the scrambling parameters
 * can be patched for ANSI compliance if standard changes
 */

static const u_char plcs_control_c_u[17] = "PLC_CNTRL_C_U=\0\0" ;

static const u_char plcs_control_c_s[17] = "PLC_CNTRL_C_S=\01\02" ;


#define PLCS_CONTROL_C_U (plcs_control_c_u[14] | (plcs_control_c_u[15]<<8))

#define PLCS_CONTROL_C_S (plcs_control_c_s[14] | (plcs_control_c_s[15]<<8))
#endif	/* nMOT_ELM */

/*
 * external vars
 */
/* struct definition see 'cmtdef.h' (also used by CFM) */


#define PS_OFF		0

#define PS_BIT3		1

#define PS_BIT4		2

#define PS_BIT7		3

#define PS_LCT		4

#define PS_BIT8		5

#define PS_JOIN		6

#define PS_ACTIVE	7


#define LCT_LEM_MAX	255

/*
 * PLC timing parameter
 */


#define PLC_MS(m)	((int)((0x10000L-(m*100000L/2048))))

#define SLOW_TL_MIN	PLC_MS(6)

#define SLOW_C_MIN	PLC_MS(10)


static	const struct plt {
	
int	timer ;			/* relative plc timer address */
	
int	para ;			/* default timing parameters */
} 
pltm[] = {
	{ PL_C_MIN, SLOW_C_MIN },	/* min t. to remain Connect State */
	{ PL_TL_MIN, SLOW_TL_MIN },	/* min t. to transmit a Line State */
	{ PL_TB_MIN, TP_TB_MIN },	/* min break time */
	{ PL_T_OUT, TP_T_OUT },		/* Signaling timeout */
	{ PL_LC_LENGTH, TP_LC_LENGTH },	/* Link Confidence Test Time */
	{ PL_T_SCRUB, TP_T_SCRUB },	/* Scrub Time == MAC TVX time ! */
	{ PL_NS_MAX, TP_NS_MAX },	/* max t. that noise is tolerated */
	{ 0,0 }
} ;

/*
 * interrupt mask
 */
#ifdef	SUPERNET_3
/*
 * Do we need the EBUF error during signaling, too, to detect SUPERNET_3
 * PLL bug?
 */

static const int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
			PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;
#else	/* SUPERNET_3 */
/*
 * We do NOT need the elasticity buffer error during signaling.
 */

static int plc_imsk_na = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
			PL_PCM_ENABLED | PL_SELF_TEST ;
#endif	/* SUPERNET_3 */

static const int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK |
			PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;

/* internal functions */
static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd);
static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy);
static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy);
static void reset_lem_struct(struct s_phy *phy);
static void plc_init(struct s_smc *smc, int p);
static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold);
static void sm_ph_lem_stop(struct s_smc *smc, int np);
static void sm_ph_linestate(struct s_smc *smc, int phy, int ls);
static void real_init_plc(struct s_smc *smc);

/*
 * SMT timer interface
 *      start PCM timer 0
 */

static void start_pcm_timer0(struct s_smc *smc, u_long value, int event, struct s_phy *phy) { phy->timer0_exp = FALSE ; /* clear timer event flag */ smt_timer_start(smc,&phy->pcm_timer0,value, EV_TOKEN(EVENT_PCM+phy->np,event)) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git4892.31%150.00%
stephen hemmingerstephen hemminger47.69%150.00%
Total52100.00%2100.00%

/* * SMT timer interface * stop PCM timer 0 */
static void stop_pcm_timer0(struct s_smc *smc, struct s_phy *phy) { if (phy->pcm_timer0.tm_active) smt_timer_stop(smc,&phy->pcm_timer0) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3294.12%150.00%
stephen hemmingerstephen hemminger25.88%150.00%
Total34100.00%2100.00%

/* init PCM state machine (called by driver) clear all PCM vars and flags */
void pcm_init(struct s_smc *smc) { int i ; int np ; struct s_phy *phy ; struct fddi_mib_p *mib ; for (np = 0,phy = smc->y ; np < NUMPHYS ; np++,phy++) { /* Indicates the type of PHY being used */ mib = phy->mib ; mib->fddiPORTPCMState = ACTIONS(PC0_OFF) ; phy->np = np ; switch (smc->s.sas) { #ifdef CONCENTRATOR case SMT_SAS : mib->fddiPORTMy_Type = (np == PS) ? TS : TM ; break ; case SMT_DAS : mib->fddiPORTMy_Type = (np == PA) ? TA : (np == PB) ? TB : TM ; break ; case SMT_NAC : mib->fddiPORTMy_Type = TM ; break; #else case SMT_SAS : mib->fddiPORTMy_Type = (np == PS) ? TS : TNONE ; mib->fddiPORTHardwarePresent = (np == PS) ? TRUE : FALSE ; #ifndef SUPERNET_3 smc->y[PA].mib->fddiPORTPCMState = PC0_OFF ; #else smc->y[PB].mib->fddiPORTPCMState = PC0_OFF ; #endif break ; case SMT_DAS : mib->fddiPORTMy_Type = (np == PB) ? TB : TA ; break ; #endif } /* * set PMD-type */ phy->pmd_scramble = 0 ; switch (phy->pmd_type[PMD_SK_PMD]) { case 'P' : mib->fddiPORTPMDClass = MIB_PMDCLASS_MULTI ; break ; case 'L' : mib->fddiPORTPMDClass = MIB_PMDCLASS_LCF ; break ; case 'D' : mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; break ; case 'S' : mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; phy->pmd_scramble = TRUE ; break ; case 'U' : mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; phy->pmd_scramble = TRUE ; break ; case '1' : mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; break ; case '2' : mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; break ; case '3' : mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE2 ; break ; case '4' : mib->fddiPORTPMDClass = MIB_PMDCLASS_SINGLE1 ; break ; case 'H' : mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; break ; case 'I' : mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; break ; case 'G' : mib->fddiPORTPMDClass = MIB_PMDCLASS_TP ; break ; default: mib->fddiPORTPMDClass = MIB_PMDCLASS_UNKNOWN ; break ; } /* * A and B port can be on primary and secondary path */ switch (mib->fddiPORTMy_Type) { case TA : mib->fddiPORTAvailablePaths |= MIB_PATH_S ; mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; mib->fddiPORTRequestedPaths[2] = MIB_P_PATH_LOCAL | MIB_P_PATH_CON_ALTER | MIB_P_PATH_SEC_PREFER ; mib->fddiPORTRequestedPaths[3] = MIB_P_PATH_LOCAL | MIB_P_PATH_CON_ALTER | MIB_P_PATH_SEC_PREFER | MIB_P_PATH_THRU ; break ; case TB : mib->fddiPORTAvailablePaths |= MIB_PATH_S ; mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; mib->fddiPORTRequestedPaths[2] = MIB_P_PATH_LOCAL | MIB_P_PATH_PRIM_PREFER ; mib->fddiPORTRequestedPaths[3] = MIB_P_PATH_LOCAL | MIB_P_PATH_PRIM_PREFER | MIB_P_PATH_CON_PREFER | MIB_P_PATH_THRU ; break ; case TS : mib->fddiPORTAvailablePaths |= MIB_PATH_S ; mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; mib->fddiPORTRequestedPaths[2] = MIB_P_PATH_LOCAL | MIB_P_PATH_CON_ALTER | MIB_P_PATH_PRIM_PREFER ; mib->fddiPORTRequestedPaths[3] = MIB_P_PATH_LOCAL | MIB_P_PATH_CON_ALTER | MIB_P_PATH_PRIM_PREFER ; break ; case TM : mib->fddiPORTRequestedPaths[1] = MIB_P_PATH_LOCAL ; mib->fddiPORTRequestedPaths[2] = MIB_P_PATH_LOCAL | MIB_P_PATH_SEC_ALTER | MIB_P_PATH_PRIM_ALTER ; mib->fddiPORTRequestedPaths[3] = 0 ; break ; } phy->pc_lem_fail = FALSE ; mib->fddiPORTPCMStateX = mib->fddiPORTPCMState ; mib->fddiPORTLCTFail_Ct = 0 ; mib->fddiPORTBS_Flag = 0 ; mib->fddiPORTCurrentPath = MIB_PATH_ISOLATED ; mib->fddiPORTNeighborType = TNONE ; phy->ls_flag = 0 ; phy->rc_flag = 0 ; phy->tc_flag = 0 ; phy->td_flag = 0 ; if (np >= PM) phy->phy_name = '0' + np - PM ; else phy->phy_name = 'A' + np ; phy->wc_flag = FALSE ; /* set by SMT */ memset((char *)&phy->lem,0,sizeof(struct lem_counter)) ; reset_lem_struct(phy) ; memset((char *)&phy->plc,0,sizeof(struct s_plc)) ; phy->plc.p_state = PS_OFF ; for (i = 0 ; i < NUMBITS ; i++) { phy->t_next[i] = 0 ; } } real_init_plc(smc) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git74099.87%150.00%
stephen hemmingerstephen hemminger10.13%150.00%
Total741100.00%2100.00%


void init_plc(struct s_smc *smc) { SK_UNUSED(smc) ; /* * dummy * this is an obsolete public entry point that has to remain * for compat. It is used by various drivers. * the work is now done in real_init_plc() * which is called from pcm_init() ; */ }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git1593.75%150.00%
stephen hemmingerstephen hemminger16.25%150.00%
Total16100.00%2100.00%


static void real_init_plc(struct s_smc *smc) { int p ; for (p = 0 ; p < NUMPHYS ; p++) plc_init(smc,p) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3397.06%150.00%
stephen hemmingerstephen hemminger12.94%150.00%
Total34100.00%2100.00%


static void plc_init(struct s_smc *smc, int p) { int i ; #ifndef MOT_ELM int rev ; /* Revision of PLC-x */ #endif /* MOT_ELM */ /* transit PCM state machine to MAINT state */ outpw(PLC(p,PL_CNTRL_B),0) ; outpw(PLC(p,PL_CNTRL_B),PL_PCM_STOP) ; outpw(PLC(p,PL_CNTRL_A),0) ; /* * if PLC-S then set control register C */ #ifndef MOT_ELM rev = inpw(PLC(p,PL_STATUS_A)) & PLC_REV_MASK ; if (rev != PLC_REVISION_A) #endif /* MOT_ELM */ { if (smc->y[p].pmd_scramble) { outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_S) ; #ifdef MOT_ELM outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_S) ; outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_S) ; #endif /* MOT_ELM */ } else { outpw(PLC(p,PL_CNTRL_C),PLCS_CONTROL_C_U) ; #ifdef MOT_ELM outpw(PLC(p,PL_T_FOT_ASS),PLCS_FASSERT_U) ; outpw(PLC(p,PL_T_FOT_DEASS),PLCS_FDEASSERT_U) ; #endif /* MOT_ELM */ } } /* * set timer register */ for ( i = 0 ; pltm[i].timer; i++) /* set timer parameter reg */ outpw(PLC(p,pltm[i].timer),pltm[i].para) ; (void)inpw(PLC(p,PL_INTR_EVENT)) ; /* clear interrupt event reg */ plc_clear_irq(smc,p) ; outpw(PLC(p,PL_INTR_MASK),plc_imsk_na); /* enable non active irq's */ /* * if PCM is configured for class s, it will NOT go to the * REMOVE state if offline (page 3-36;) * in the concentrator, all inactive PHYS always must be in * the remove state * there's no real need to use this feature at all .. */ #ifndef CONCENTRATOR if ((smc->s.sas == SMT_SAS) && (p == PS)) { outpw(PLC(p,PL_CNTRL_B),PL_CLASS_S) ; } #endif }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git30399.34%150.00%
stephen hemmingerstephen hemminger20.66%150.00%
Total305100.00%2100.00%

/* * control PCM state machine */
static void plc_go_state(struct s_smc *smc, int p, int state) { HW_PTR port ; int val ; SK_UNUSED(smc) ; port = (HW_PTR) (PLC(p,PL_CNTRL_B)) ; val = inpw(port) & ~(PL_PCM_CNTRL | PL_MAINT) ; outpw(port,val) ; outpw(port,val | state) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git6995.83%150.00%
stephen hemmingerstephen hemminger34.17%150.00%
Total72100.00%2100.00%

/* * read current line state (called by ECM & PCM) */
int sm_pm_get_ls(struct s_smc *smc, int phy) { int state ; #ifdef CONCENTRATOR if (!plc_is_installed(smc,phy)) return PC_QLS; #endif state = inpw(PLC(phy,PL_STATUS_A)) & PL_LINE_ST ; switch(state) { case PL_L_QLS: state = PC_QLS ; break ; case PL_L_MLS: state = PC_MLS ; break ; case PL_L_HLS: state = PC_HLS ; break ; case PL_L_ILS4: case PL_L_ILS16: state = PC_ILS ; break ; case PL_L_ALS: state = PC_LS_PDR ; break ; default : state = PC_LS_NONE ; } return state; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git10398.10%150.00%
stephen hemmingerstephen hemminger21.90%150.00%
Total105100.00%2100.00%


static int plc_send_bits(struct s_smc *smc, struct s_phy *phy, int len) { int np = phy->np ; /* PHY index */ int n ; int i ; SK_UNUSED(smc) ; /* create bit vector */ for (i = len-1,n = 0 ; i >= 0 ; i--) { n = (n<<1) | phy->t_val[phy->bitn+i] ; } if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { #if 0 printf("PL_PCM_SIGNAL is set\n") ; #endif return 1; } /* write bit[n] & length = 1 to regs */ outpw(PLC(np,PL_VECTOR_LEN),len-1) ; /* len=nr-1 */ outpw(PLC(np,PL_XMIT_VECTOR),n) ; #ifdef DEBUG #if 1 #ifdef DEBUG_BRD if (smc->debug.d_plc & 0x80) #else if (debug.d_plc & 0x80) #endif printf("SIGNALING bit %d .. %d\n",phy->bitn,phy->bitn+len-1) ; #endif #endif return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git18498.40%150.00%
stephen hemmingerstephen hemminger31.60%150.00%
Total187100.00%2100.00%

/* * config plc muxes */
void plc_config_mux(struct s_smc *smc, int mux) { if (smc->s.sas != SMT_DAS) return ; if (mux == MUX_WRAPB) { SETMASK(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; SETMASK(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; } else { CLEAR(PLC(PA,PL_CNTRL_B),PL_CONFIG_CNTRL) ; CLEAR(PLC(PA,PL_CNTRL_A),PL_SC_REM_LOOP) ; } CLEAR(PLC(PB,PL_CNTRL_B),PL_CONFIG_CNTRL) ; CLEAR(PLC(PB,PL_CNTRL_A),PL_SC_REM_LOOP) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git10998.20%150.00%
stephen hemmingerstephen hemminger21.80%150.00%
Total111100.00%2100.00%

/* PCM state machine called by dispatcher & fddi_init() (driver) do display state change process event until SM is stable */
void pcm(struct s_smc *smc, const int np, int event) { int state ; int oldstate ; struct s_phy *phy ; struct fddi_mib_p *mib ; #ifndef CONCENTRATOR /* * ignore 2nd PHY if SAS */ if ((np != PS) && (smc->s.sas == SMT_SAS)) return ; #endif phy = &smc->y[np] ; mib = phy->mib ; oldstate = mib->fddiPORTPCMState ; do { DB_PCM("PCM %c: state %s", phy->phy_name, (mib->fddiPORTPCMState & AFLAG) ? "ACTIONS " : "") ; DB_PCM("%s, event %s\n", pcm_states[mib->fddiPORTPCMState & ~AFLAG], pcm_events[event]) ; state = mib->fddiPORTPCMState ; pcm_fsm(smc,phy,event) ; event = 0 ; } while (state != mib->fddiPORTPCMState) ; /* * because the PLC does the bit signaling for us, * we're always in SIGNAL state * the MIB want's to see CONNECT * we therefore fake an entry in the MIB */ if (state == PC5_SIGNAL) mib->fddiPORTPCMStateX = PC3_CONNECT ; else mib->fddiPORTPCMStateX = state ; #ifndef SLIM_SMT /* * path change */ if ( mib->fddiPORTPCMState != oldstate && ((oldstate == PC8_ACTIVE) || (mib->fddiPORTPCMState == PC8_ACTIVE))) { smt_srf_event(smc,SMT_EVENT_PORT_PATH_CHANGE, (int) (INDEX_PORT+ phy->np),0) ; } #endif #ifdef FDDI_MIB /* check whether a snmp-trap has to be sent */ if ( mib->fddiPORTPCMState != oldstate ) { /* a real state change took place */ DB_SNMP ("PCM from %d to %d\n", oldstate, mib->fddiPORTPCMState); if ( mib->fddiPORTPCMState == PC0_OFF ) { /* send first trap */ snmp_fddi_trap (smc, 1, (int) mib->fddiPORTIndex ); } else if ( oldstate == PC0_OFF ) { /* send second trap */ snmp_fddi_trap (smc, 2, (int) mib->fddiPORTIndex ); } else if ( mib->fddiPORTPCMState != PC2_TRACE && oldstate == PC8_ACTIVE ) { /* send third trap */ snmp_fddi_trap (smc, 3, (int) mib->fddiPORTIndex ); } else if ( mib->fddiPORTPCMState == PC8_ACTIVE ) { /* send fourth trap */ snmp_fddi_trap (smc, 4, (int) mib->fddiPORTIndex ); } } #endif pcm_state_change(smc,np,state) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git36399.18%150.00%
stephen hemmingerstephen hemminger30.82%150.00%
Total366100.00%2100.00%

/* * PCM state machine */
static void pcm_fsm(struct s_smc *smc, struct s_phy *phy, int cmd) { int i ; int np = phy->np ; /* PHY index */ struct s_plc *plc ; struct fddi_mib_p *mib ; #ifndef MOT_ELM u_short plc_rev ; /* Revision of the plc */ #endif /* nMOT_ELM */ plc = &phy->plc ; mib = phy->mib ; /* * general transitions independent of state */ switch (cmd) { case PC_STOP : /*PC00-PC80*/ if (mib->fddiPORTPCMState != PC9_MAINT) { GO_STATE(PC0_OFF) ; AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) FDDI_PORT_EVENT, (u_long) FDDI_PORT_STOP, smt_get_port_event_word(smc)); } return ; case PC_START : /*PC01-PC81*/ if (mib->fddiPORTPCMState != PC9_MAINT) GO_STATE(PC1_BREAK) ; return ; case PC_DISABLE : /* PC09-PC99 */ GO_STATE(PC9_MAINT) ; AIX_EVENT(smc, (u_long) FDDI_RING_STATUS, (u_long) FDDI_PORT_EVENT, (u_long) FDDI_PORT_DISABLED, smt_get_port_event_word(smc)); return ; case PC_TIMEOUT_LCT : /* if long or extended LCT */ stop_pcm_timer0(smc,phy) ; CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; /* end of LCT is indicate by PCM_CODE (initiate PCM event) */ return ; } switch(mib->fddiPORTPCMState) { case ACTIONS(PC0_OFF) : stop_pcm_timer0(smc,phy) ; outpw(PLC(np,PL_CNTRL_A),0) ; CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; sm_ph_lem_stop(smc,np) ; /* disable LEM */ phy->cf_loop = FALSE ; phy->cf_join = FALSE ; queue_event(smc,EVENT_CFM,CF_JOIN+np) ; plc_go_state(smc,np,PL_PCM_STOP) ; mib->fddiPORTConnectState = PCM_DISABLED ; ACTIONS_DONE() ; break ; case PC0_OFF: /*PC09*/ if (cmd == PC_MAINT) { GO_STATE(PC9_MAINT) ; break ; } break ; case ACTIONS(PC1_BREAK) : /* Stop the LCT timer if we came from Signal state */ stop_pcm_timer0(smc,phy) ; ACTIONS_DONE() ; plc_go_state(smc,np,0) ; CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; sm_ph_lem_stop(smc,np) ; /* disable LEM */ /* * if vector is already loaded, go to OFF to clear PCM_SIGNAL */ #if 0 if (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL) { plc_go_state(smc,np,PL_PCM_STOP) ; /* TB_MIN ? */ } #endif /* * Go to OFF state in any case. */ plc_go_state(smc,np,PL_PCM_STOP) ; if (mib->fddiPORTPC_Withhold == PC_WH_NONE) mib->fddiPORTConnectState = PCM_CONNECTING ; phy->cf_loop = FALSE ; phy->cf_join = FALSE ; queue_event(smc,EVENT_CFM,CF_JOIN+np) ; phy->ls_flag = FALSE ; phy->pc_mode = PM_NONE ; /* needed by CFM */ phy->bitn = 0 ; /* bit signaling start bit */ for (i = 0 ; i < 3 ; i++) pc_tcode_actions(smc,i,phy) ; /* Set the non-active interrupt mask register */ outpw(PLC(np,PL_INTR_MASK),plc_imsk_na) ; /* * If the LCT was stopped. There might be a * PCM_CODE interrupt event present. * This must be cleared. */ (void)inpw(PLC(np,PL_INTR_EVENT)) ; #ifndef MOT_ELM /* Get the plc revision for revision dependent code */ plc_rev = inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK ; if (plc_rev != PLC_REV_SN3) #endif /* MOT_ELM */ { /* * No supernet III PLC, so set Xmit verctor and * length BEFORE starting the state machine. */ if (plc_send_bits(smc,phy,3)) { return ; } } /* * Now give the Start command. * - The start command shall be done before setting the bits * to be signaled. (In PLC-S description and PLCS in SN3. * - The start command shall be issued AFTER setting the * XMIT vector and the XMIT length register. * * We do it exactly according this specs for the old PLC and * the new PLCS inside the SN3. * For the usual PLCS we try it the way it is done for the * old PLC and set the XMIT registers again, if the PLC is * not in SIGNAL state. This is done according to an PLCS * errata workaround. */ plc_go_state(smc,np,PL_PCM_START) ; /* * workaround for PLC-S eng. sample errata */ #ifdef MOT_ELM if (!(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) #else /* nMOT_ELM */ if (((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) != PLC_REVISION_A) && !(inpw(PLC(np,PL_STATUS_B)) & PL_PCM_SIGNAL)) #endif /* nMOT_ELM */ { /* * Set register again (PLCS errata) or the first time * (new SN3 PLCS). */ (void) plc_send_bits(smc,phy,3) ; } /* * end of workaround */ GO_STATE(PC5_SIGNAL) ; plc->p_state = PS_BIT3 ; plc->p_bits = 3 ; plc->p_start = 0 ; break ; case PC1_BREAK : break ; case ACTIONS(PC2_TRACE) : plc_go_state(smc,np,PL_PCM_TRACE) ; ACTIONS_DONE() ; break ; case PC2_TRACE : break ; case PC3_CONNECT : /* these states are done by hardware */ case PC4_NEXT : break ; case ACTIONS(PC5_SIGNAL) : ACTIONS_DONE() ; case PC5_SIGNAL : if ((cmd != PC_SIGNAL) && (cmd != PC_TIMEOUT_LCT)) break ; switch (plc->p_state) { case PS_BIT3 : for (i = 0 ; i <= 2 ; i++) pc_rcode_actions(smc,i,phy) ; pc_tcode_actions(smc,3,phy) ; plc->p_state = PS_BIT4 ; plc->p_bits = 1 ; plc->p_start = 3 ; phy->bitn = 3 ; if (plc_send_bits(smc,phy,1)) { return ; } break ; case PS_BIT4 : pc_rcode_actions(smc,3,phy) ; for (i = 4 ; i <= 6 ; i++) pc_tcode_actions(smc,i,phy) ; plc->p_state = PS_BIT7 ; plc->p_bits = 3 ; plc->p_start = 4 ; phy->bitn = 4 ; if (plc_send_bits(smc,phy,3)) { return ; } break ; case PS_BIT7 : for (i = 3 ; i <= 6 ; i++) pc_rcode_actions(smc,i,phy) ; plc->p_state = PS_LCT ; plc->p_bits = 0 ; plc->p_start = 7 ; phy->bitn = 7 ; sm_ph_lem_start(smc,np,(int)smc->s.lct_short) ; /* enable LEM */ /* start LCT */ i = inpw(PLC(np,PL_CNTRL_B)) & ~PL_PC_LOOP ; outpw(PLC(np,PL_CNTRL_B),i) ; /* must be cleared */ outpw(PLC(np,PL_CNTRL_B),i | PL_RLBP) ; break ; case PS_LCT : /* check for local LCT failure */ pc_tcode_actions(smc,7,phy) ; /* * set tval[7] */ plc->p_state = PS_BIT8 ; plc->p_bits = 1 ; plc->p_start = 7 ; phy->bitn = 7 ; if (plc_send_bits(smc,phy,1)) { return ; } break ; case PS_BIT8 : /* check for remote LCT failure */ pc_rcode_actions(smc,7,phy) ; if (phy->t_val[7] || phy->r_val[7]) { plc_go_state(smc,np,PL_PCM_STOP) ; GO_STATE(PC1_BREAK) ; break ; } for (i = 8 ; i <= 9 ; i++) pc_tcode_actions(smc,i,phy) ; plc->p_state = PS_JOIN ; plc->p_bits = 2 ; plc->p_start = 8 ; phy->bitn = 8 ; if (plc_send_bits(smc,phy,2)) { return ; } break ; case PS_JOIN : for (i = 8 ; i <= 9 ; i++) pc_rcode_actions(smc,i,phy) ; plc->p_state = PS_ACTIVE ; GO_STATE(PC6_JOIN) ; break ; } break ; case ACTIONS(PC6_JOIN) : /* * prevent mux error when going from WRAP_A to WRAP_B */ if (smc->s.sas == SMT_DAS && np == PB && (smc->y[PA].pc_mode == PM_TREE || smc->y[PB].pc_mode == PM_TREE)) { SETMASK(PLC(np,PL_CNTRL_A), PL_SC_REM_LOOP,PL_SC_REM_LOOP) ; SETMASK(PLC(np,PL_CNTRL_B), PL_CONFIG_CNTRL,PL_CONFIG_CNTRL) ; } SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; SETMASK(PLC(np,PL_CNTRL_B),PL_PC_JOIN,PL_PC_JOIN) ; ACTIONS_DONE() ; cmd = 0 ; /* fall thru */ case PC6_JOIN : switch (plc->p_state) { case PS_ACTIVE: /*PC88b*/ if (!phy->cf_join) { phy->cf_join = TRUE ; queue_event(smc,EVENT_CFM,CF_JOIN+np) ; } if (cmd == PC_JOIN) GO_STATE(PC8_ACTIVE) ; /*PC82*/ if (cmd == PC_TRACE) { GO_STATE(PC2_TRACE) ; break ; } break ; } break ; case PC7_VERIFY : break ; case ACTIONS(PC8_ACTIVE) : /* * start LEM for SMT */ sm_ph_lem_start(smc,(int)phy->np,LCT_LEM_MAX) ; phy->tr_flag = FALSE ; mib->fddiPORTConnectState = PCM_ACTIVE ; /* Set the active interrupt mask register */ outpw(PLC(np,PL_INTR_MASK),plc_imsk_act) ; ACTIONS_DONE() ; break ; case PC8_ACTIVE : /*PC81 is done by PL_TNE_EXPIRED irq */ /*PC82*/ if (cmd == PC_TRACE) { GO_STATE(PC2_TRACE) ; break ; } /*PC88c: is done by TRACE_PROP irq */ break ; case ACTIONS(PC9_MAINT) : stop_pcm_timer0(smc,phy) ; CLEAR(PLC(np,PL_CNTRL_B),PL_PC_JOIN) ; CLEAR(PLC(np,PL_CNTRL_B),PL_LONG) ; CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; /* disable LEM int. */ sm_ph_lem_stop(smc,np) ; /* disable LEM */ phy->cf_loop = FALSE ; phy->cf_join = FALSE ; queue_event(smc,EVENT_CFM,CF_JOIN+np) ; plc_go_state(smc,np,PL_PCM_STOP) ; mib->fddiPORTConnectState = PCM_DISABLED ; SETMASK(PLC(np,PL_CNTRL_B),PL_MAINT,PL_MAINT) ; sm_ph_linestate(smc,np,(int) MIB2LS(mib->fddiPORTMaint_LS)) ; outpw(PLC(np,PL_CNTRL_A),PL_SC_BYPASS) ; ACTIONS_DONE() ; break ; case PC9_MAINT : DB_PCMN(1,"PCM %c : MAINT\n",phy->phy_name,0) ; /*PC90*/ if (cmd == PC_ENABLE) { GO_STATE(PC0_OFF) ; break ; } break ; default: SMT_PANIC(smc,SMT_E0118, SMT_E0118_MSG) ; break ; } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git161999.75%133.33%
stephen hemmingerstephen hemminger30.18%133.33%
steven colesteven cole10.06%133.33%
Total1623100.00%3100.00%

/* * force line state on a PHY output (only in MAINT state) */
static void sm_ph_linestate(struct s_smc *smc, int phy, int ls) { int cntrl ; SK_UNUSED(smc) ; cntrl = (inpw(PLC(phy,PL_CNTRL_B)) & ~PL_MAINT_LS) | PL_PCM_STOP | PL_MAINT ; switch(ls) { case PC_QLS: /* Force Quiet */ cntrl |= PL_M_QUI0 ; break ; case PC_MLS: /* Force Master */ cntrl |= PL_M_MASTR ; break ; case PC_HLS: /* Force Halt */ cntrl |= PL_M_HALT ; break ; default : case PC_ILS: /* Force Idle */ cntrl |= PL_M_IDLE ; break ; case PC_LS_PDR: /* Enable repeat filter */ cntrl |= PL_M_TPDR ; break ; } outpw(PLC(phy,PL_CNTRL_B),cntrl) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git10797.27%150.00%
stephen hemmingerstephen hemminger32.73%150.00%
Total110100.00%2100.00%


static void reset_lem_struct(struct s_phy *phy) { struct lem_counter *lem = &phy->lem ; phy->mib->fddiPORTLer_Estimate = 15 ; lem->lem_float_ber = 15 * 100 ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3697.30%150.00%
stephen hemmingerstephen hemminger12.70%150.00%
Total37100.00%2100.00%

/* * link error monitor */
static void lem_evaluate(struct s_smc *smc, struct s_phy *phy) { int ber ; u_long errors ; struct lem_counter *lem = &phy->lem ; struct fddi_mib_p *mib ; int cond ; mib = phy->mib ; if (!lem->lem_on) return ; errors = inpw(PLC(((int) phy->np),PL_LINK_ERR_CTR)) ; lem->lem_errors += errors ; mib->fddiPORTLem_Ct += errors ; errors = lem->lem_errors ; /* * calculation is called on a intervall of 8 seconds * -> this means, that one error in 8 sec. is one of 8*125*10E6 * the same as BER = 10E-9 * Please note: * -> 9 errors in 8 seconds mean: * BER = 9 * 10E-9 and this is * < 10E-8, so the limit of 10E-8 is not reached! */ if (!errors) ber = 15 ; else if (errors <= 9) ber = 9 ; else if (errors <= 99) ber = 8 ; else if (errors <= 999) ber = 7 ; else if (errors <= 9999) ber = 6 ; else if (errors <= 99999) ber = 5 ; else if (errors <= 999999) ber = 4 ; else if (errors <= 9999999) ber = 3 ; else if (errors <= 99999999) ber = 2 ; else if (errors <= 999999999) ber = 1 ; else ber = 0 ; /* * weighted average */ ber *= 100 ; lem->lem_float_ber = lem->lem_float_ber * 7 + ber * 3 ; lem->lem_float_ber /= 10 ; mib->fddiPORTLer_Estimate = lem->lem_float_ber / 100 ; if (mib->fddiPORTLer_Estimate < 4) { mib->fddiPORTLer_Estimate = 4 ; } if (lem->lem_errors) { DB_PCMN(1,"LEM %c :\n",phy->np == PB? 'B' : 'A',0) ; DB_PCMN(1,"errors : %ld\n",lem->lem_errors,0) ; DB_PCMN(1,"sum_errors : %ld\n",mib->fddiPORTLem_Ct,0) ; DB_PCMN(1,"current BER : 10E-%d\n",ber/100,0) ; DB_PCMN(1,"float BER : 10E-(%d/100)\n",lem->lem_float_ber,0) ; DB_PCMN(1,"avg. BER : 10E-%d\n", mib->fddiPORTLer_Estimate,0) ; } lem->lem_errors = 0L ; #ifndef SLIM_SMT cond = (mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Alarm) ? TRUE : FALSE ; #ifdef SMT_EXT_CUTOFF smt_ler_alarm_check(smc,phy,cond) ; #endif /* nSMT_EXT_CUTOFF */ if (cond != mib->fddiPORTLerFlag) { smt_srf_event(smc,SMT_COND_PORT_LER, (int) (INDEX_PORT+ phy->np) ,cond) ; } #endif if ( mib->fddiPORTLer_Estimate <= mib->fddiPORTLer_Cutoff) { phy->pc_lem_fail = TRUE ; /* flag */ mib->fddiPORTLem_Reject_Ct++ ; /* * "forgive 10e-2" if we cutoff so we can come * up again .. */ lem->lem_float_ber += 2*100 ; /*PC81b*/ #ifdef CONCENTRATOR DB_PCMN(1,"PCM: LER cutoff on port %d cutoff %d\n", phy->np, mib->fddiPORTLer_Cutoff) ; #endif #ifdef SMT_EXT_CUTOFF smt_port_off_event(smc,phy->np); #else /* nSMT_EXT_CUTOFF */ queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; #endif /* nSMT_EXT_CUTOFF */ } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git50899.61%150.00%
stephen hemmingerstephen hemminger20.39%150.00%
Total510100.00%2100.00%

/* * called by SMT to calculate LEM bit error rate */
void sm_lem_evaluate(struct s_smc *smc) { int np ; for (np = 0 ; np < NUMPHYS ; np++) lem_evaluate(smc,&smc->y[np]) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3897.44%150.00%
stephen hemmingerstephen hemminger12.56%150.00%
Total39100.00%2100.00%


static void lem_check_lct(struct s_smc *smc, struct s_phy *phy) { struct lem_counter *lem = &phy->lem ; struct fddi_mib_p *mib ; int errors ; mib = phy->mib ; phy->pc_lem_fail = FALSE ; /* flag */ errors = inpw(PLC(((int)phy->np),PL_LINK_ERR_CTR)) ; lem->lem_errors += errors ; mib->fddiPORTLem_Ct += errors ; if (lem->lem_errors) { switch(phy->lc_test) { case LC_SHORT: if (lem->lem_errors >= smc->s.lct_short) phy->pc_lem_fail = TRUE ; break ; case LC_MEDIUM: if (lem->lem_errors >= smc->s.lct_medium) phy->pc_lem_fail = TRUE ; break ; case LC_LONG: if (lem->lem_errors >= smc->s.lct_long) phy->pc_lem_fail = TRUE ; break ; case LC_EXTENDED: if (lem->lem_errors >= smc->s.lct_extended) phy->pc_lem_fail = TRUE ; break ; } DB_PCMN(1," >>errors : %d\n",lem->lem_errors,0) ; } if (phy->pc_lem_fail) { mib->fddiPORTLCTFail_Ct++ ; mib->fddiPORTLem_Reject_Ct++ ; } else mib->fddiPORTLCTFail_Ct = 0 ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git21899.09%150.00%
stephen hemmingerstephen hemminger20.91%150.00%
Total220100.00%2100.00%

/* * LEM functions */
static void sm_ph_lem_start(struct s_smc *smc, int np, int threshold) { struct lem_counter *lem = &smc->y[np].lem ; lem->lem_on = 1 ; lem->lem_errors = 0L ; /* Do NOT reset mib->fddiPORTLer_Estimate here. It is called too * often. */ outpw(PLC(np,PL_LE_THRESHOLD),threshold) ; (void)inpw(PLC(np,PL_LINK_ERR_CTR)) ; /* clear error counter */ /* enable LE INT */ SETMASK(PLC(np,PL_INTR_MASK),PL_LE_CTR,PL_LE_CTR) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git8396.51%150.00%
stephen hemmingerstephen hemminger33.49%150.00%
Total86100.00%2100.00%


static void sm_ph_lem_stop(struct s_smc *smc, int np) { struct lem_counter *lem = &smc->y[np].lem ; lem->lem_on = 0 ; CLEAR(PLC(np,PL_INTR_MASK),PL_LE_CTR) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git4595.74%150.00%
stephen hemmingerstephen hemminger24.26%150.00%
Total47100.00%2100.00%

/* ARGSUSED */
void sm_pm_ls_latch(struct s_smc *smc, int phy, int on_off) /* int on_off; en- or disable ident. ls */ { SK_UNUSED(smc) ; phy = phy ; on_off = on_off ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2686.67%150.00%
stephen hemmingerstephen hemminger413.33%150.00%
Total30100.00%2100.00%

/* * PCM pseudo code * receive actions are called AFTER the bit n is received, * i.e. if pc_rcode_actions(5) is called, bit 6 is the next bit to be received */ /* * PCM pseudo code 5.1 .. 6.1 */
static void pc_rcode_actions(struct s_smc *smc, int bit, struct s_phy *phy) { struct fddi_mib_p *mib ; mib = phy->mib ; DB_PCMN(1,"SIG rec %x %x:\n", bit,phy->r_val[bit] ) ; bit++ ; switch(bit) { case 0: case 1: case 2: break ; case 3 : if (phy->r_val[1] == 0 && phy->r_val[2] == 0) mib->fddiPORTNeighborType = TA ; else if (phy->r_val[1] == 0 && phy->r_val[2] == 1) mib->fddiPORTNeighborType = TB ; else if (phy->r_val[1] == 1 && phy->r_val[2] == 0) mib->fddiPORTNeighborType = TS ; else if (phy->r_val[1] == 1 && phy->r_val[2] == 1) mib->fddiPORTNeighborType = TM ; break ; case 4: if (mib->fddiPORTMy_Type == TM && mib->fddiPORTNeighborType == TM) { DB_PCMN(1,"PCM %c : E100 withhold M-M\n", phy->phy_name,0) ; mib->fddiPORTPC_Withhold = PC_WH_M_M ; RS_SET(smc,RS_EVENT) ; } else if (phy->t_val[3] || phy->r_val[3]) { mib->fddiPORTPC_Withhold = PC_WH_NONE ; if (mib->fddiPORTMy_Type == TM || mib->fddiPORTNeighborType == TM) phy->pc_mode = PM_TREE ; else phy->pc_mode = PM_PEER ; /* reevaluate the selection criteria (wc_flag) */ all_selection_criteria (smc); if (phy->wc_flag) { mib->fddiPORTPC_Withhold = PC_WH_PATH ; } } else { mib->fddiPORTPC_Withhold = PC_WH_OTHER ; RS_SET(smc,RS_EVENT) ; DB_PCMN(1,"PCM %c : E101 withhold other\n", phy->phy_name,0) ; } phy->twisted = ((mib->fddiPORTMy_Type != TS) && (mib->fddiPORTMy_Type != TM) && (mib->fddiPORTNeighborType == mib->fddiPORTMy_Type)) ; if (phy->twisted) { DB_PCMN(1,"PCM %c : E102 !!! TWISTED !!!\n", phy->phy_name,0) ; } break ; case 5 : break ; case 6: if (phy->t_val[4] || phy->r_val[4]) { if ((phy->t_val[4] && phy->t_val[5]) || (phy->r_val[4] && phy->r_val[5]) ) phy->lc_test = LC_EXTENDED ; else phy->lc_test = LC_LONG ; } else if (phy->t_val[5] || phy->r_val[5]) phy->lc_test = LC_MEDIUM ; else phy->lc_test = LC_SHORT ; switch (phy->lc_test) { case LC_SHORT : /* 50ms */ outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LENGTH ) ; phy->t_next[7] = smc->s.pcm_lc_short ; break ; case LC_MEDIUM : /* 500ms */ outpw(PLC((int)phy->np,PL_LC_LENGTH), TP_LC_LONGLN ) ; phy->t_next[7] = smc->s.pcm_lc_medium ; break ; case LC_LONG : SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; phy->t_next[7] = smc->s.pcm_lc_long ; break ; case LC_EXTENDED : SETMASK(PLC((int)phy->np,PL_CNTRL_B),PL_LONG,PL_LONG) ; phy->t_next[7] = smc->s.pcm_lc_extended ; break ; } if (phy->t_next[7] > smc->s.pcm_lc_medium) { start_pcm_timer0(smc,phy->t_next[7],PC_TIMEOUT_LCT,phy); } DB_PCMN(1,"LCT timer = %ld us\n", phy->t_next[7], 0) ; phy->t_next[9] = smc->s.pcm_t_next_9 ; break ; case 7: if (phy->t_val[6]) { phy->cf_loop = TRUE ; } phy->td_flag = TRUE ; break ; case 8: if (phy->t_val[7] || phy->r_val[7]) { DB_PCMN(1,"PCM %c : E103 LCT fail %s\n", phy->phy_name,phy->t_val[7]? "local":"remote") ; queue_event(smc,(int)(EVENT_PCM+phy->np),PC_START) ; } break ; case 9: if (phy->t_val[8] || phy->r_val[8]) { if (phy->t_val[8]) phy->cf_loop = TRUE ; phy->td_flag = TRUE ; } break ; case 10: if (phy->r_val[9]) { /* neighbor intends to have MAC on output */ ; mib->fddiPORTMacIndicated.R_val = TRUE ; } else { /* neighbor does not intend to have MAC on output */ ; mib->fddiPORTMacIndicated.R_val = FALSE ; } break ; } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git85799.54%133.33%
stephen hemmingerstephen hemminger30.35%133.33%
frans popfrans pop10.12%133.33%
Total861100.00%3100.00%

/* * PCM pseudo code 5.1 .. 6.1 */
static void pc_tcode_actions(struct s_smc *smc, const int bit, struct s_phy *phy) { int np = phy->np ; struct fddi_mib_p *mib ; mib = phy->mib ; switch(bit) { case 0: phy->t_val[0] = 0 ; /* no escape used */ break ; case 1: if (mib->fddiPORTMy_Type == TS || mib->fddiPORTMy_Type == TM) phy->t_val[1] = 1 ; else phy->t_val[1] = 0 ; break ; case 2 : if (mib->fddiPORTMy_Type == TB || mib->fddiPORTMy_Type == TM) phy->t_val[2] = 1 ; else phy->t_val[2] = 0 ; break ; case 3: { int type,ne ; int policy ; type = mib->fddiPORTMy_Type ; ne = mib->fddiPORTNeighborType ; policy = smc->mib.fddiSMTConnectionPolicy ; phy->t_val[3] = 1 ; /* Accept connection */ switch (type) { case TA : if ( ((policy & POLICY_AA) && ne == TA) || ((policy & POLICY_AB) && ne == TB) || ((policy & POLICY_AS) && ne == TS) || ((policy & POLICY_AM) && ne == TM) ) phy->t_val[3] = 0 ; /* Reject */ break ; case TB : if ( ((policy & POLICY_BA) && ne == TA) || ((policy & POLICY_BB) && ne == TB) || ((policy & POLICY_BS) && ne == TS) || ((policy & POLICY_BM) && ne == TM) ) phy->t_val[3] = 0 ; /* Reject */ break ; case TS : if ( ((policy & POLICY_SA) && ne == TA) || ((policy & POLICY_SB) && ne == TB) || ((policy & POLICY_SS) && ne == TS) || ((policy & POLICY_SM) && ne == TM) ) phy->t_val[3] = 0 ; /* Reject */ break ; case TM : if ( ne == TM || ((policy & POLICY_MA) && ne == TA) || ((policy & POLICY_MB) && ne == TB) || ((policy & POLICY_MS) && ne == TS) || ((policy & POLICY_MM) && ne == TM) ) phy->t_val[3] = 0 ; /* Reject */ break ; } #ifndef SLIM_SMT /* * detect undesirable connection attempt event */ if ( (type == TA && ne == TA ) || (type == TA && ne == TS ) || (type == TB && ne == TB ) || (type == TB && ne == TS ) || (type == TS && ne == TA ) || (type == TS && ne == TB ) ) { smt_srf_event(smc,SMT_EVENT_PORT_CONNECTION, (int) (INDEX_PORT+ phy->np) ,0) ; } #endif } break ; case 4: if (mib->fddiPORTPC_Withhold == PC_WH_NONE) { if (phy->pc_lem_fail) { phy->t_val[4] = 1 ; /* long */ phy->t_val[5] = 0 ; } else { phy->t_val[4] = 0 ; if (mib->fddiPORTLCTFail_Ct > 0) phy->t_val[5] = 1 ; /* medium */ else phy->t_val[5] = 0 ; /* short */ /* * Implementers choice: use medium * instead of short when undesired * connection attempt is made. */ if (phy->wc_flag) phy->t_val[5] = 1 ; /* medium */ } mib->fddiPORTConnectState = PCM_CONNECTING ; } else { mib->fddiPORTConnectState = PCM_STANDBY ; phy->t_val[4] = 1 ; /* extended */ phy->t_val[5] = 1 ; } break ; case 5: break ; case 6: /* we do NOT have a MAC for LCT */ phy->t_val[6] = 0 ; break ; case 7: phy->cf_loop = FALSE ; lem_check_lct(smc,phy) ; if (phy->pc_lem_fail) { DB_PCMN(1,"PCM %c : E104 LCT failed\n", phy->phy_name,0) ; phy->t_val[7] = 1 ; } else phy->t_val[7] = 0 ; break ; case 8: phy->t_val[8] = 0 ; /* Don't request MAC loopback */ break ; case 9: phy->cf_loop = 0 ; if ((mib->fddiPORTPC_Withhold != PC_WH_NONE) || ((smc->s.sas == SMT_DAS) && (phy->wc_flag))) { queue_event(smc,EVENT_PCM+np,PC_START) ; break ; } phy->t_val[9] = FALSE ; switch (smc->s.sas) { case SMT_DAS : /* * MAC intended on output */ if (phy->pc_mode == PM_TREE) { if ((np == PB) || ((np == PA) && (smc->y[PB].mib->fddiPORTConnectState != PCM_ACTIVE))) phy->t_val[9] = TRUE ; } else { if (np == PB) phy->t_val[9] = TRUE ; } break ; case SMT_SAS : if (np == PS) phy->t_val[9] = TRUE ; break ; #ifdef CONCENTRATOR case SMT_NAC : /* * MAC intended on output */ if (np == PB) phy->t_val[9] = TRUE ; break ; #endif } mib->fddiPORTMacIndicated.T_val = phy->t_val[9] ; break ; } DB_PCMN(1,"SIG snd %x %x:\n", bit,phy->t_val[bit] ) ; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git96799.59%133.33%
stephen hemmingerstephen hemminger30.31%133.33%
frans popfrans pop10.10%133.33%
Total971100.00%3100.00%

/* * return status twisted (called by SMT) */
int pcm_status_twisted(struct s_smc *smc) { int twist = 0 ; if (smc->s.sas != SMT_DAS) return 0; if (smc->y[PA].twisted && (smc->y[PA].mib->fddiPORTPCMState == PC8_ACTIVE)) twist |= 1 ; if (smc->y[PB].twisted && (smc->y[PB].mib->fddiPORTPCMState == PC8_ACTIVE)) twist |= 2 ; return twist; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git9098.90%150.00%
stephen hemmingerstephen hemminger11.10%150.00%
Total91100.00%2100.00%

/* * return status (called by SMT) * type * state * remote phy type * remote mac yes/no */
void pcm_status_state(struct s_smc *smc, int np, int *type, int *state, int *remote, int *mac) { struct s_phy *phy = &smc->y[np] ; struct fddi_mib_p *mib ; mib = phy->mib ; /* remote PHY type and MAC - set only if active */ *mac = 0 ; *type = mib->fddiPORTMy_Type ; /* our PHY type */ *state = mib->fddiPORTConnectState ; *remote = mib->fddiPORTNeighborType ; switch(mib->fddiPORTPCMState) { case PC8_ACTIVE : *mac = mib->fddiPORTMacIndicated.R_val ; break ; } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git9694.12%150.00%
stephen hemmingerstephen hemminger65.88%150.00%
Total102100.00%2100.00%

/* * return rooted station status (called by SMT) */
int pcm_rooted_station(struct s_smc *smc) { int n ; for (n = 0 ; n < NUMPHYS ; n++) { if (smc->y[n].mib->fddiPORTPCMState == PC8_ACTIVE && smc->y[n].mib->fddiPORTNeighborType == TM) return 0; } return 1; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git6198.39%150.00%
stephen hemmingerstephen hemminger11.61%150.00%
Total62100.00%2100.00%

/* * Interrupt actions for PLC & PCM events */
void plc_irq(struct s_smc *smc, int np, unsigned int cmd) /* int np; PHY index */ { struct s_phy *phy = &smc->y[np] ; struct s_plc *plc = &phy->plc ; int n ; #ifdef SUPERNET_3 int corr_mask ; #endif /* SUPERNET_3 */ int i ; if (np >= smc->s.numphys) { plc->soft_err++ ; return ; } if (cmd & PL_EBUF_ERR) { /* elastic buff. det. over-|underflow*/ /* * Check whether the SRF Condition occurred. */ if (!plc->ebuf_cont && phy->mib->fddiPORTPCMState == PC8_ACTIVE){ /* * This is the real Elasticity Error. * More than one in a row are treated as a * single one. * Only count this in the active state. */ phy->mib->fddiPORTEBError_Ct ++ ; } plc->ebuf_err++ ; if (plc->ebuf_cont <= 1000) { /* * Prevent counter from being wrapped after * hanging years in that interrupt. */ plc->ebuf_cont++ ; /* Ebuf continuous error */ } #ifdef SUPERNET_3 if (plc->ebuf_cont == 1000 && ((inpw(PLC(np,PL_STATUS_A)) & PLC_REV_MASK) == PLC_REV_SN3)) { /* * This interrupt remeained high for at least * 1000 consecutive interrupt calls. * * This is caused by a hardware error of the * ORION part of the Supernet III chipset. * * Disable this bit from the mask. */ corr_mask = (plc_imsk_na & ~PL_EBUF_ERR) ; outpw(PLC(np,PL_INTR_MASK),corr_mask); /* * Disconnect from the ring. * Call the driver with the reset indication. */ queue_event(smc,EVENT_ECM,EC_DISCONNECT) ; /* * Make an error log entry. */ SMT_ERR_LOG(smc,SMT_E0136, SMT_E0136_MSG) ; /* * Indicate the Reset. */ drv_reset_indication(smc) ; } #endif /* SUPERNET_3 */ } else { /* Reset the continuous error variable */ plc->ebuf_cont = 0 ; /* reset Ebuf continuous error */ } if (cmd & PL_PHYINV) { /* physical layer invalid signal */ plc->phyinv++ ; } if (cmd & PL_VSYM_CTR) { /* violation symbol counter has incr.*/ plc->vsym_ctr++ ; } if (cmd & PL_MINI_CTR) { /* dep. on PLC_CNTRL_A's MINI_CTR_INT*/ plc->mini_ctr++ ; } if (cmd & PL_LE_CTR) { /* link error event counter */ int j ; /* * note: PL_LINK_ERR_CTR MUST be read to clear it */ j = inpw(PLC(np,PL_LE_THRESHOLD)) ; i = inpw(PLC(np,PL_LINK_ERR_CTR)) ; if (i < j) { /* wrapped around */ i += 256 ; } if (phy->lem.lem_on) { /* Note: Lem errors shall only be counted when * link is ACTIVE or LCT is active. */ phy->lem.lem_errors += i ; phy->mib->fddiPORTLem_Ct += i ; } } if (cmd & PL_TPC_EXPIRED) { /* TPC timer reached zero */ if (plc->p_state == PS_LCT) { /* * end of LCT */ ; } plc->tpc_exp++ ; } if (cmd & PL_LS_MATCH) { /* LS == LS in PLC_CNTRL_B's MATCH_LS*/ switch (inpw(PLC(np,PL_CNTRL_B)) & PL_MATCH_LS) { case PL_I_IDLE : phy->curr_ls = PC_ILS ; break ; case PL_I_HALT : phy->curr_ls = PC_HLS ; break ; case PL_I_MASTR : phy->curr_ls = PC_MLS ; break ; case PL_I_QUIET : phy->curr_ls = PC_QLS ; break ; } } if (cmd & PL_PCM_BREAK) { /* PCM has entered the BREAK state */ int reason; reason = inpw(PLC(np,PL_STATUS_B)) & PL_BREAK_REASON ; switch (reason) { case PL_B_PCS : plc->b_pcs++ ; break ; case PL_B_TPC : plc->b_tpc++ ; break ; case PL_B_TNE : plc->b_tne++ ; break ; case PL_B_QLS : plc->b_qls++ ; break ; case PL_B_ILS : plc->b_ils++ ; break ; case PL_B_HLS : plc->b_hls++ ; break ; } /*jd 05-Aug-1999 changed: Bug #10419 */ DB_PCMN(1,"PLC %d: MDcF = %x\n", np, smc->e.DisconnectFlag); if (smc->e.DisconnectFlag == FALSE) { DB_PCMN(1,"PLC %d: restart (reason %x)\n", np, reason); queue_event(smc,EVENT_PCM+np,PC_START) ; } else { DB_PCMN(1,"PLC %d: NO!! restart (reason %x)\n", np, reason); } return ; } /* * If both CODE & ENABLE are set ignore enable */ if (cmd & PL_PCM_CODE) { /* receive last sign.-bit | LCT complete */ queue_event(smc,EVENT_PCM+np,PC_SIGNAL) ; n = inpw(PLC(np,PL_RCV_VECTOR)) ; for (i = 0 ; i < plc->p_bits ; i++) { phy->r_val[plc->p_start+i] = n & 1 ; n >>= 1 ; } } else if (cmd & PL_PCM_ENABLED) { /* asserted SC_JOIN, scrub.completed*/ queue_event(smc,EVENT_PCM+np,PC_JOIN) ; } if (cmd & PL_TRACE_PROP) { /* MLS while PC8_ACTIV || PC2_TRACE */ /*PC22b*/ if (!phy->tr_flag) { DB_PCMN(1,"PCM : irq TRACE_PROP %d %d\n", np,smc->mib.fddiSMTECMState) ; phy->tr_flag = TRUE ; smc->e.trace_prop |= ENTITY_BIT(ENTITY_PHY(np)) ; queue_event(smc,EVENT_ECM,EC_TRACE_PROP) ; } } /* * filter PLC glitch ??? * QLS || HLS only while in PC2_TRACE state */ if ((cmd & PL_SELF_TEST) && (phy->mib->fddiPORTPCMState == PC2_TRACE)) { /*PC22a*/ if (smc->e.path_test == PT_PASSED) { DB_PCMN(1,"PCM : state = %s %d\n", get_pcmstate(smc,np), phy->mib->fddiPORTPCMState) ; smc->e.path_test = PT_PENDING ; queue_event(smc,EVENT_ECM,EC_PATH_TEST) ; } } if (cmd & PL_TNE_EXPIRED) { /* TNE: length of noise events */ /* break_required (TNE > NS_Max) */ if (phy->mib->fddiPORTPCMState == PC8_ACTIVE) { if (!phy->tr_flag) { DB_PCMN(1,"PCM %c : PC81 %s\n",phy->phy_name,"NSE"); queue_event(smc,EVENT_PCM+np,PC_START) ; return ; } } } #if 0 if (cmd & PL_NP_ERR) { /* NP has requested to r/w an inv reg*/ /* * It's a bug by AMD */ plc->np_err++ ; } /* pin inactiv (GND) */ if (cmd & PL_PARITY_ERR) { /* p. error dedected on TX9-0 inp */ plc->parity_err++ ; } if (cmd & PL_LSDO) { /* carrier detected */ ; } #endif }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git87299.09%125.00%
stephen hemmingerstephen hemminger40.45%125.00%
lucas de marchilucas de marchi30.34%125.00%
linus torvaldslinus torvalds10.11%125.00%
Total880100.00%4100.00%

#ifdef DEBUG /* * fill state struct */
void pcm_get_state(struct s_smc *smc, struct smt_state *state) { struct s_phy *phy ; struct pcm_state *pcs ; int i ; int ii ; short rbits ; short tbits ; struct fddi_mib_p *mib ; for (i = 0, phy = smc->y, pcs = state->pcm_state ; i < NUMPHYS ; i++ , phy++, pcs++ ) { mib = phy->mib ; pcs->pcm_type = (u_char) mib->fddiPORTMy_Type ; pcs->pcm_state = (u_char) mib->fddiPORTPCMState ; pcs->pcm_mode = phy->pc_mode ; pcs->pcm_neighbor = (u_char) mib->fddiPORTNeighborType ; pcs->pcm_bsf = mib->fddiPORTBS_Flag ; pcs->pcm_lsf = phy->ls_flag ; pcs->pcm_lct_fail = (u_char) mib->fddiPORTLCTFail_Ct ; pcs->pcm_ls_rx = LS2MIB(sm_pm_get_ls(smc,i)) ; for (ii = 0, rbits = tbits = 0 ; ii < NUMBITS ; ii++) { rbits <<= 1 ; tbits <<= 1 ; if (phy->r_val[NUMBITS-1-ii]) rbits |= 1 ; if (phy->t_val[NUMBITS-1-ii]) tbits |= 1 ; } pcs->pcm_r_val = rbits ; pcs->pcm_t_val = tbits ; } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git23699.16%150.00%
stephen hemmingerstephen hemminger20.84%150.00%
Total238100.00%2100.00%


int get_pcm_state(struct s_smc *smc, int np) { int pcs ; SK_UNUSED(smc) ; switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { case PL_PC0 : pcs = PC_STOP ; break ; case PL_PC1 : pcs = PC_START ; break ; case PL_PC2 : pcs = PC_TRACE ; break ; case PL_PC3 : pcs = PC_SIGNAL ; break ; case PL_PC4 : pcs = PC_SIGNAL ; break ; case PL_PC5 : pcs = PC_SIGNAL ; break ; case PL_PC6 : pcs = PC_JOIN ; break ; case PL_PC7 : pcs = PC_JOIN ; break ; case PL_PC8 : pcs = PC_ENABLE ; break ; case PL_PC9 : pcs = PC_MAINT ; break ; default : pcs = PC_DISABLE ; break ; } return pcs; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git12498.41%150.00%
stephen hemmingerstephen hemminger21.59%150.00%
Total126100.00%2100.00%


char *get_linestate(struct s_smc *smc, int np) { char *ls = "" ; SK_UNUSED(smc) ; switch (inpw(PLC(np,PL_STATUS_A)) & PL_LINE_ST) { case PL_L_NLS : ls = "NOISE" ; break ; case PL_L_ALS : ls = "ACTIV" ; break ; case PL_L_UND : ls = "UNDEF" ; break ; case PL_L_ILS4: ls = "ILS 4" ; break ; case PL_L_QLS : ls = "QLS" ; break ; case PL_L_MLS : ls = "MLS" ; break ; case PL_L_HLS : ls = "HLS" ; break ; case PL_L_ILS16:ls = "ILS16" ; break ; #ifdef lint default: ls = "unknown" ; break ; #endif } return ls; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git11798.32%150.00%
stephen hemmingerstephen hemminger21.68%150.00%
Total119100.00%2100.00%


char *get_pcmstate(struct s_smc *smc, int np) { char *pcs ; SK_UNUSED(smc) ; switch (inpw(PLC(np,PL_STATUS_B)) & PL_PCM_STATE) { case PL_PC0 : pcs = "OFF" ; break ; case PL_PC1 : pcs = "BREAK" ; break ; case PL_PC2 : pcs = "TRACE" ; break ; case PL_PC3 : pcs = "CONNECT"; break ; case PL_PC4 : pcs = "NEXT" ; break ; case PL_PC5 : pcs = "SIGNAL" ; break ; case PL_PC6 : pcs = "JOIN" ; break ; case PL_PC7 : pcs = "VERIFY" ; break ; case PL_PC8 : pcs = "ACTIV" ; break ; case PL_PC9 : pcs = "MAINT" ; break ; default : pcs = "UNKNOWN" ; break ; } return pcs; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git12698.44%150.00%
stephen hemmingerstephen hemminger21.56%150.00%
Total128100.00%2100.00%


void list_phy(struct s_smc *smc) { struct s_plc *plc ; int np ; for (np = 0 ; np < NUMPHYS ; np++) { plc = &smc->y[np].plc ; printf("PHY %d:\tERRORS\t\t\tBREAK_REASONS\t\tSTATES:\n",np) ; printf("\tsoft_error: %ld \t\tPC_Start : %ld\n", plc->soft_err,plc->b_pcs); printf("\tparity_err: %ld \t\tTPC exp. : %ld\t\tLine: %s\n", plc->parity_err,plc->b_tpc,get_linestate(smc,np)) ; printf("\tebuf_error: %ld \t\tTNE exp. : %ld\n", plc->ebuf_err,plc->b_tne) ; printf("\tphyinvalid: %ld \t\tQLS det. : %ld\t\tPCM : %s\n", plc->phyinv,plc->b_qls,get_pcmstate(smc,np)) ; printf("\tviosym_ctr: %ld \t\tILS det. : %ld\n", plc->vsym_ctr,plc->b_ils) ; printf("\tmingap_ctr: %ld \t\tHLS det. : %ld\n", plc->mini_ctr,plc->b_hls) ; printf("\tnodepr_err: %ld\n",plc->np_err) ; printf("\tTPC_exp : %ld\n",plc->tpc_exp) ; printf("\tLEM_err : %ld\n",smc->y[np].lem.lem_errors) ; } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git17799.44%150.00%
stephen hemmingerstephen hemminger10.56%150.00%
Total178100.00%2100.00%

#ifdef CONCENTRATOR
void pcm_lem_dump(struct s_smc *smc) { int i ; struct s_phy *phy ; struct fddi_mib_p *mib ; char *entostring() ; printf("PHY errors BER\n") ; printf("----------------------\n") ; for (i = 0,phy = smc->y ; i < NUMPHYS ; i++,phy++) { if (!plc_is_installed(smc,i)) continue ; mib = phy->mib ; printf("%s\t%ld\t10E-%d\n", entostring(smc,ENTITY_PHY(i)), mib->fddiPORTLem_Ct, mib->fddiPORTLer_Estimate) ; } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git10199.02%150.00%
stephen hemmingerstephen hemminger10.98%150.00%
Total102100.00%2100.00%

#endif #endif

Overall Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git906998.05%114.29%
stephen hemmingerstephen hemminger1701.84%114.29%
lucas de marchilucas de marchi30.03%114.29%
frans popfrans pop20.02%114.29%
steven colesteven cole20.02%114.29%
arjan van de venarjan van de ven20.02%114.29%
linus torvaldslinus torvalds10.01%114.29%
Total9249100.00%7100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}