📄 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 lintstatic const char ID_sccs[] = "@(#)pcmplc.c 2.55 99/08/05 (C) SK " ;#endif#ifdef FDDI_MIBextern int snmp_fddi_trap(#ifdef ANSICstruct s_smc * smc, int type, int index#endif);#endif#ifdef CONCENTRATORextern int plc_is_installed(#ifdef ANSICstruct 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 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 int plc_imsk_act = PL_PCM_CODE | PL_TRACE_PROP | PL_PCM_BREAK | PL_PCM_ENABLED | PL_SELF_TEST | PL_EBUF_ERR;/* external functions */void all_selection_criteria(struct s_smc *smc);/* 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)) ;}/* * 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) ;}/* 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) ;}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() ; */}static void real_init_plc(struct s_smc *smc){ int p ; for (p = 0 ; p < NUMPHYS ; p++) plc_init(smc,p) ;}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}/* * 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) ;}/* * read current line state (called by ECM & PCM) */int sm_pm_get_ls(struct s_smc *smc, int phy){ int state ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -