📄 fplustm.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. * ******************************************************************************//* * FORMAC+ Driver for tag mode */#include "h/types.h"#include "h/fddi.h"#include "h/smc.h"#include "h/supern_2.h"#include "can.c"#ifndef lintstatic const char ID_sccs[] = "@(#)fplustm.c 1.32 99/02/23 (C) SK " ;#endif#ifndef UNUSED#ifdef lint#define UNUSED(x) (x) = (x)#else#define UNUSED(x)#endif#endif#define FM_ADDRX (FM_ADDET|FM_EXGPA0|FM_EXGPA1)#define MS2BCLK(x) ((x)*12500L)#define US2BCLK(x) ((x)*1250L)/* * prototypes for static function */static void build_claim_beacon(struct s_smc *smc, u_long t_request);static int init_mac(struct s_smc *smc, int all);static void rtm_init(struct s_smc *smc);static void smt_split_up_fifo(struct s_smc *smc);#if (!defined(NO_SMT_PANIC) || defined(DEBUG))static char write_mdr_warning [] = "E350 write_mdr() FM_SNPPND is set\n";static char cam_warning [] = "E_SMT_004: CAM still busy\n";#endif#define DUMMY_READ() smc->hw.mc_dummy = (u_short) inp(ADDR(B0_RAP))#define CHECK_NPP() { unsigned k = 10000 ;\ while ((inpw(FM_A(FM_STMCHN)) & FM_SNPPND) && k) k--;\ if (!k) { \ SMT_PANIC(smc,SMT_E0130, SMT_E0130_MSG) ; \ } \ }#define CHECK_CAM() { unsigned k = 10 ;\ while (!(inpw(FM_A(FM_AFSTAT)) & FM_DONE) && k) k--;\ if (!k) { \ SMT_PANIC(smc,SMT_E0131, SMT_E0131_MSG) ; \ } \ }const struct fddi_addr fddi_broadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};static const struct fddi_addr null_addr = {{0,0,0,0,0,0}};static const struct fddi_addr dbeacon_multi = {{0x01,0x80,0xc2,0x00,0x01,0x00}};static const u_short my_said = 0xffff ; /* short address (n.u.) */static const u_short my_sagp = 0xffff ; /* short group address (n.u.) *//* * define my address */#ifdef USE_CAN_ADDR#define MA smc->hw.fddi_canon_addr#else#define MA smc->hw.fddi_home_addr#endif/* * useful interrupt bits */static int mac_imsk1u = FM_STXABRS | FM_STXABRA0 | FM_SXMTABT ;static int mac_imsk1l = FM_SQLCKS | FM_SQLCKA0 | FM_SPCEPDS | FM_SPCEPDA0| FM_STBURS | FM_STBURA0 ; /* delete FM_SRBFL after tests */static int mac_imsk2u = FM_SERRSF | FM_SNFSLD | FM_SRCVOVR | FM_SRBFL | FM_SMYCLM ;static int mac_imsk2l = FM_STRTEXR | FM_SDUPCLM | FM_SFRMCTR | FM_SERRCTR | FM_SLSTCTR | FM_STRTEXP | FM_SMULTDA | FM_SRNGOP ;static int mac_imsk3u = FM_SRCVOVR2 | FM_SRBFL2 ;static int mac_imsk3l = FM_SRPERRQ2 | FM_SRPERRQ1 ;static int mac_beacon_imsk2u = FM_SOTRBEC | FM_SMYBEC | FM_SBEC | FM_SLOCLM | FM_SHICLM | FM_SMYCLM | FM_SCLM ;static u_long mac_get_tneg(struct s_smc *smc){ u_long tneg ; tneg = (u_long)((long)inpw(FM_A(FM_TNEG))<<5) ; return((u_long)((tneg + ((inpw(FM_A(FM_TMRS))>>10)&0x1f)) | 0xffe00000L)) ;}void mac_update_counter(struct s_smc *smc){ smc->mib.m[MAC0].fddiMACFrame_Ct = (smc->mib.m[MAC0].fddiMACFrame_Ct & 0xffff0000L) + (u_short) inpw(FM_A(FM_FCNTR)) ; smc->mib.m[MAC0].fddiMACLost_Ct = (smc->mib.m[MAC0].fddiMACLost_Ct & 0xffff0000L) + (u_short) inpw(FM_A(FM_LCNTR)) ; smc->mib.m[MAC0].fddiMACError_Ct = (smc->mib.m[MAC0].fddiMACError_Ct & 0xffff0000L) + (u_short) inpw(FM_A(FM_ECNTR)) ; smc->mib.m[MAC0].fddiMACT_Neg = mac_get_tneg(smc) ;#ifdef SMT_REAL_TOKEN_CT /* * If the token counter is emulated it is updated in smt_event. */ TBD#else smt_emulate_token_ct( smc, MAC0 );#endif}/* * write long value into buffer memory over memory data register (MDR), */static void write_mdr(struct s_smc *smc, u_long val){ CHECK_NPP() ; MDRW(val) ;}#if 0/* * read long value from buffer memory over memory data register (MDR), */static u_long read_mdr(struct s_smc *smc, unsigned int addr){ long p ; CHECK_NPP() ; MARR(addr) ; outpw(FM_A(FM_CMDREG1),FM_IRMEMWO) ; CHECK_NPP() ; /* needed for PCI to prevent from timeing violations *//* p = MDRR() ; */ /* bad read values if the workaround */ /* smc->hw.mc_dummy = *((short volatile far *)(addr)))*/ /* is used */ p = (u_long)inpw(FM_A(FM_MDRU))<<16 ; p += (u_long)inpw(FM_A(FM_MDRL)) ; return(p) ;}#endif/* * clear buffer memory */static void init_ram(struct s_smc *smc){ u_short i ; smc->hw.fp.fifo.rbc_ram_start = 0 ; smc->hw.fp.fifo.rbc_ram_end = smc->hw.fp.fifo.rbc_ram_start + RBC_MEM_SIZE ; CHECK_NPP() ; MARW(smc->hw.fp.fifo.rbc_ram_start) ; for (i = smc->hw.fp.fifo.rbc_ram_start; i < (u_short) (smc->hw.fp.fifo.rbc_ram_end-1); i++) write_mdr(smc,0L) ; /* Erase the last byte too */ write_mdr(smc,0L) ;}/* * set receive FIFO pointer */static void set_recvptr(struct s_smc *smc){ /* * initialize the pointer for receive queue 1 */ outpw(FM_A(FM_RPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* RPR1 */ outpw(FM_A(FM_SWPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* SWPR1 */ outpw(FM_A(FM_WPR1),smc->hw.fp.fifo.rx1_fifo_start) ; /* WPR1 */ outpw(FM_A(FM_EARV1),smc->hw.fp.fifo.tx_s_start-1) ; /* EARV1 */ /* * initialize the pointer for receive queue 2 */ if (smc->hw.fp.fifo.rx2_fifo_size) { outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rx2_fifo_start) ; outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rx2_fifo_start) ; outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rx2_fifo_start) ; outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; } else { outpw(FM_A(FM_RPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; outpw(FM_A(FM_SWPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; outpw(FM_A(FM_WPR2),smc->hw.fp.fifo.rbc_ram_end-1) ; outpw(FM_A(FM_EARV2),smc->hw.fp.fifo.rbc_ram_end-1) ; }}/* * set transmit FIFO pointer */static void set_txptr(struct s_smc *smc){ outpw(FM_A(FM_CMDREG2),FM_IRSTQ) ; /* reset transmit queues */ /* * initialize the pointer for asynchronous transmit queue */ outpw(FM_A(FM_RPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* RPXA0 */ outpw(FM_A(FM_SWPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* SWPXA0 */ outpw(FM_A(FM_WPXA0),smc->hw.fp.fifo.tx_a0_start) ; /* WPXA0 */ outpw(FM_A(FM_EAA0),smc->hw.fp.fifo.rx2_fifo_start-1) ; /* EAA0 */ /* * initialize the pointer for synchronous transmit queue */ if (smc->hw.fp.fifo.tx_s_size) { outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_s_start) ; outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_s_start) ; outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_s_start) ; outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; } else { outpw(FM_A(FM_RPXS),smc->hw.fp.fifo.tx_a0_start-1) ; outpw(FM_A(FM_SWPXS),smc->hw.fp.fifo.tx_a0_start-1) ; outpw(FM_A(FM_WPXS),smc->hw.fp.fifo.tx_a0_start-1) ; outpw(FM_A(FM_EAS),smc->hw.fp.fifo.tx_a0_start-1) ; }}/* * init memory buffer management registers */static void init_rbc(struct s_smc *smc){ u_short rbc_ram_addr ; /* * set unused pointers or permanent pointers */ rbc_ram_addr = smc->hw.fp.fifo.rx2_fifo_start - 1 ; outpw(FM_A(FM_RPXA1),rbc_ram_addr) ; /* a1-send pointer */ outpw(FM_A(FM_WPXA1),rbc_ram_addr) ; outpw(FM_A(FM_SWPXA1),rbc_ram_addr) ; outpw(FM_A(FM_EAA1),rbc_ram_addr) ; set_recvptr(smc) ; set_txptr(smc) ;}/* * init rx pointer */static void init_rx(struct s_smc *smc){ struct s_smt_rx_queue *queue ; /* * init all tx data structures for receive queue 1 */ smc->hw.fp.rx[QUEUE_R1] = queue = &smc->hw.fp.rx_q[QUEUE_R1] ; queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R1_CSR) ; queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R1_DA) ; /* * init all tx data structures for receive queue 2 */ smc->hw.fp.rx[QUEUE_R2] = queue = &smc->hw.fp.rx_q[QUEUE_R2] ; queue->rx_bmu_ctl = (HW_PTR) ADDR(B0_R2_CSR) ; queue->rx_bmu_dsc = (HW_PTR) ADDR(B4_R2_DA) ;}/* * set the TSYNC register of the FORMAC to regulate synchronous transmission */void set_formac_tsync(struct s_smc *smc, long sync_bw){ outpw(FM_A(FM_TSYNC),(unsigned int) (((-sync_bw) >> 5) & 0xffff) ) ;}/* * init all tx data structures */static void init_tx(struct s_smc *smc){ struct s_smt_tx_queue *queue ; /* * init all tx data structures for the synchronous queue */ smc->hw.fp.tx[QUEUE_S] = queue = &smc->hw.fp.tx_q[QUEUE_S] ; queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XS_CSR) ; queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XS_DA) ;#ifdef ESS set_formac_tsync(smc,smc->ess.sync_bw) ;#endif /* * init all tx data structures for the asynchronous queue 0 */ smc->hw.fp.tx[QUEUE_A0] = queue = &smc->hw.fp.tx_q[QUEUE_A0] ; queue->tx_bmu_ctl = (HW_PTR) ADDR(B0_XA_CSR) ; queue->tx_bmu_dsc = (HW_PTR) ADDR(B5_XA_DA) ; llc_recover_tx(smc) ;}static void mac_counter_init(struct s_smc *smc){ int i ; u_long *ec ; /* * clear FORMAC+ frame-, lost- and error counter */ outpw(FM_A(FM_FCNTR),0) ; outpw(FM_A(FM_LCNTR),0) ; outpw(FM_A(FM_ECNTR),0) ; /* * clear internal error counter stucture */ ec = (u_long *)&smc->hw.fp.err_stats ; for (i = (sizeof(struct err_st)/sizeof(long)) ; i ; i--) *ec++ = 0L ; smc->mib.m[MAC0].fddiMACRingOp_Ct = 0 ;}/* * set FORMAC address, and t_request */static void set_formac_addr(struct s_smc *smc){ long t_requ = smc->mib.m[MAC0].fddiMACT_Req ; outpw(FM_A(FM_SAID),my_said) ; /* set short address */ outpw(FM_A(FM_LAIL),(unsigned)((smc->hw.fddi_home_addr.a[4]<<8) + smc->hw.fddi_home_addr.a[5])) ; outpw(FM_A(FM_LAIC),(unsigned)((smc->hw.fddi_home_addr.a[2]<<8) + smc->hw.fddi_home_addr.a[3])) ; outpw(FM_A(FM_LAIM),(unsigned)((smc->hw.fddi_home_addr.a[0]<<8) + smc->hw.fddi_home_addr.a[1])) ; outpw(FM_A(FM_SAGP),my_sagp) ; /* set short group address */ outpw(FM_A(FM_LAGL),(unsigned)((smc->hw.fp.group_addr.a[4]<<8) + smc->hw.fp.group_addr.a[5])) ; outpw(FM_A(FM_LAGC),(unsigned)((smc->hw.fp.group_addr.a[2]<<8) + smc->hw.fp.group_addr.a[3])) ; outpw(FM_A(FM_LAGM),(unsigned)((smc->hw.fp.group_addr.a[0]<<8) + smc->hw.fp.group_addr.a[1])) ; /* set r_request regs. (MSW & LSW of TRT ) */ outpw(FM_A(FM_TREQ1),(unsigned)(t_requ>>16)) ; outpw(FM_A(FM_TREQ0),(unsigned)t_requ) ;}static void set_int(char *p, int l){ p[0] = (char)(l >> 24) ; p[1] = (char)(l >> 16) ; p[2] = (char)(l >> 8) ; p[3] = (char)(l >> 0) ;}/* * copy TX descriptor to buffer mem * append FC field and MAC frame * if more bit is set in descr * append pointer to descriptor (endless loop) * else * append 'end of chain' pointer */static void copy_tx_mac(struct s_smc *smc, u_long td, struct fddi_mac *mac, unsigned off, int len)/* u_long td; transmit descriptor *//* struct fddi_mac *mac; mac frame pointer *//* unsigned off; start address within buffer memory *//* int len ; lenght of the frame including the FC */{ int i ; u_int *p ; CHECK_NPP() ; MARW(off) ; /* set memory address reg for writes */ p = (u_int *) mac ; for (i = (len + 3)/4 ; i ; i--) { if (i == 1) { /* last word, set the tag bit */ outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; } write_mdr(smc,MDR_REVERSE(*p)) ; p++ ; } outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ write_mdr(smc,td) ; /* write over memory data reg to buffer */}/* BEGIN_MANUAL_ENTRY(module;tests;3) How to test directed beacon frames ---------------------------------------------------------------- o Insert a break point in the function build_claim_beacon() before calling copy_tx_mac() for building the claim frame. o Modify the RM3_DETECT case so that the RM6_DETECT state will always entered from the RM3_DETECT state (function rmt_fsm(), rmt.c) o Compile the driver. o Set the parameter TREQ in the protocol.ini or net.cfg to a small value to make sure your station will win the claim process. o Start the driver. o When you reach the break point, modify the SA and DA address of the claim frame (e.g. SA = DA = 10005affffff). o When you see RM3_DETECT and RM6_DETECT, observe the direct beacon frames on the UPPSLANA. END_MANUAL_ENTRY */static void directed_beacon(struct s_smc *smc){ SK_LOC_DECL(u_int,a[2]) ; /* * set UNA in frame * enable FORMAC to send endless queue of directed beacon * important: the UNA starts at byte 1 (not at byte 0) */ * (char *) a = (char) ((long)DBEACON_INFO<<24L) ; a[1] = 0 ; memcpy((char *)a+1,(char *) &smc->mib.m[MAC0].fddiMACUpstreamNbr,6) ; CHECK_NPP() ; /* set memory address reg for writes */ MARW(smc->hw.fp.fifo.rbc_ram_start+DBEACON_FRAME_OFF+4) ; write_mdr(smc,MDR_REVERSE(a[0])) ; outpw(FM_A(FM_CMDREG2),FM_ISTTB) ; /* set the tag bit */ write_mdr(smc,MDR_REVERSE(a[1])) ; outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + DBEACON_FRAME_OFF) ;}/* setup claim & beacon pointer NOTE : special frame packets end with a pointer to their own descriptor, and the MORE bit is set in the descriptor*/static void build_claim_beacon(struct s_smc *smc, u_long t_request){ u_int td ; int len ; struct fddi_mac_sf *mac ; /* * build claim packet */ len = 17 ; td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; mac = &smc->hw.fp.mac_sfb ; mac->mac_fc = FC_CLAIM ; /* DA == SA in claim frame */ mac->mac_source = mac->mac_dest = MA ; /* 2's complement */ set_int((char *)mac->mac_info,(int)t_request) ; copy_tx_mac(smc,td,(struct fddi_mac *)mac, smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF,len) ; /* set CLAIM start pointer */ outpw(FM_A(FM_SACL),smc->hw.fp.fifo.rbc_ram_start + CLAIM_FRAME_OFF) ; /* * build beacon packet */ len = 17 ; td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; mac->mac_fc = FC_BEACON ; mac->mac_source = MA ; mac->mac_dest = null_addr ; /* DA == 0 in beacon frame */ set_int((char *) mac->mac_info,((int)BEACON_INFO<<24) + 0 ) ; copy_tx_mac(smc,td,(struct fddi_mac *)mac, smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF,len) ; /* set beacon start pointer */ outpw(FM_A(FM_SABC),smc->hw.fp.fifo.rbc_ram_start + BEACON_FRAME_OFF) ; /* * build directed beacon packet * contains optional UNA */ len = 23 ; td = TX_DESCRIPTOR | ((((u_int)len-1)&3)<<27) ; mac->mac_fc = FC_BEACON ; mac->mac_source = MA ; mac->mac_dest = dbeacon_multi ; /* multicast */ set_int((char *) mac->mac_info,((int)DBEACON_INFO<<24) + 0 ) ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -