void ASIC11096SPI::Init() { // THESE NEED TO BE CHANGED TO MATCH YOUR OWN HARDWARE // set up direction register CLRMASK(sysRegs->iop->IOPMOD, BIT(kDRDY) | BIT(kMISO)); SETMASK(sysRegs->iop->IOPMOD, BIT(kSSNOT) | BIT(kRESET) | BIT(kSCLK) | BIT(kMOSI)); // make sure the output pins are in the correct state SETMASK(sysRegs->iop->IOPDATA, BIT(kSSNOT)); CLRMASK(sysRegs->iop->IOPDATA, BIT(kRESET) | BIT(kSCLK)); }
/* * 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) ; }
void ASIC11096SPI::SetMOSI(bool high) { // THESE NEED TO BE CHANGED TO MATCH YOUR OWN HARDWARE if(high) { SETMASK(sysRegs->iop->IOPDATA, BIT(kMOSI)); } else { CLRMASK(sysRegs->iop->IOPDATA, BIT(kMOSI)); } }
/* * 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) ; }
/* * 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 ; } }
/* * 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 ; } }
void ASIC11096SPI::End() { // THESE NEED TO BE CHANGED TO MATCH YOUR OWN HARDWARE SETMASK(sysRegs->iop->IOPDATA, BIT(kSSNOT)); }
void ASIC11096SPI::Reset() { // THESE NEED TO BE CHANGED TO MATCH YOUR OWN HARDWARE SETMASK(sysRegs->iop->IOPDATA, BIT(kRESET)); CLRMASK(sysRegs->iop->IOPDATA, BIT(kRESET)); }