📄 if_pn.c
字号:
/* if_pn.c - proNET-80 network interface driver *//* Copyright 1984,1985,1986,1987,1988,1989 Wind River Systems, Inc. */extern char copyright_wind_river[]; static char *copyright=copyright_wind_river;static char sccsid[] = "@(#)if_pn.c 2.1 11/4/86 (c) 1986 Proteon, Inc.";/*modification history--------------------01k,07aug89,gae changed iv68k.h to iv.h.01j,05sep88,gae got rid of non-functional code.01i,03sep88,gae fixed bug with >2 pronets in ring.01h,20aug88,gae fixed wire-center/bootrom hang problem by disabling interrupts in pnreset(). ifdef'd out DMA stuff. got rid of gratuitous taskDelay() in pnoutput. called pnprobe() in pnattach().01g,12jul88,gae merged in Carl Reed's fixes. Lint. Cleanup. fixed pn_softc definition thanks to Phil Wiborg.01f,07jul88,jcf lint.01e,30may88,dnw changed to v4 names.01d,10may88,llk include ioLib.h for READ constants. changed vxTdelay to taskDelay.01c,08feb88,rdc fixed several races and bugs.01b,17nov87,dnw changed pnattach to take int vec num instead of vec adrs.01a,06nov87,rdc written.*//*DESCRIPTIONProNET device driver for proNET VMEbus interfaces (p1500 and p1580).The only user callable routine is: pnattach (unit, addr, ivec, ilevel)BUGSOnly one 'unit' allowed; proNet-80 (not proNet-10) is hard-coded.*/#include "vxWorks.h"#include "iv.h"#include "ioLib.h"#include "ioctl.h"#include "memLib.h"#include "etherLib.h"#include "param.h"#include "mbuf.h"#include "protosw.h"#include "socket.h"#include "errno.h"#include "if.h"#include "route.h"#ifdef INET#include "in.h"#include "in_systm.h"#include "in_var.h"#include "ip.h"#endif INET#include "if_pn.h"#include "if_ether.h"IMPORT VOID ipintr ();#define NPN 1 /* maximum number of proNET boards */#define IS_80 TRUE /* TRUE=proNET-80, FALSE=proNET-10 *//**************************************************************************//* maximum transmission unit defined -- *//* you can set PNMTU at anything from 576 on up, so long as you *//* recongnize the weaknesses of 4.2BSD in assumuing too much about *//* the MTU of other TCP/IP implementations. Thus 576 is the most *//* "compatible" value. 1536 is a popular "large" value, because *//* it is a multiple of 512, which the trailer scheme liked. *//* The absolute maximum size is 4096, which is enforced. *//**************************************************************************//* Adjust the next line for desired MTU (576 <= PNMTU). * Acceptable values are 576, 1024, 1536, 2048, 2560, 3072, 3584, 4096 */#define PNMTU 4096/* Do not to touch the next group of lines. * They check the value and set other constants based on it. */#if PNMTU>4096#undef PNMTU#define PNMTU 4096#endif PNMTU>4096#define PNMRU (PNMTU + 16)#define PNBUFSIZE (PNMRU + sizeof(struct pn_header))#define PNCMDSIZE 4096/* end of don't touch *//**************************************************************************//* debugging and tracing stuff *//**************************************************************************/int pn_tracehdr = FALSE; /* TRUE => trace headers (slowly!!) */int pn_logerrors = FALSE; /* TRUE => log all I/O errors */#define pntracehdr if (pn_tracehdr) pnprt_hdr#define pnprintf if (pn_logerrors) logMsgBOOL pn_copy = FALSE;/* XXX most boards won't allow long word transfers on 'just' even boundaries */#define pncopy(x,y,l) (pn_copy ? bcopy(x,y,l) : bcopyBytes(x,y,l))LOCAL u_short pn_modes[] = /* three operating modes */ { PN_RST, /* digital loopback */ PN_MEN, /* analog loopback */ PN_JNR|PN_MEN /* network mode */ };/**************************************************************************//* Software status of each interface. *//* *//* Each interface is referenced by a network interface structure, *//* vs_if, which the routing code uses to locate the interface. *//* Structure contains the output queue for the interface, its address, ...*//**************************************************************************/struct pn_softc { struct arpcom vs_ac; /* common Ethernet structures */#define vs_if vs_ac.ac_if /* network-visible interface */#define vs_enaddr vs_ac.ac_enaddr /* hardware ethernet address */ short vs_oactive; /* is output active */ short vs_olen; /* output length */ u_short vs_ostrt; /* output start, for retransmission */ short vs_tries; /* transmit current retry count */ short vs_init; /* number of ring inits */ short vs_refused; /* number of packets refused */ short vs_timeouts; /* number of transmit timeouts */ short vs_otimeout; /* number of output timeouts */ short vs_ibadf; /* number of input bad formats */ short vs_parity; /* number of parity errors */ u_short rcvhd; /* beginning of the rcv blk, for RBUFDMAPTR */ caddr_t vs_tbuf; /* xmt buffer */ int pnIntLevel; /* VME interrupt level */ struct pn_regs *pn_regs; } pn_softc[NPN];/* forward declarations */LOCAL int pnprobe ();LOCAL VOID pnreset ();LOCAL VOID pninit ();LOCAL int pnidentify ();LOCAL VOID pnstart ();LOCAL VOID pnxint ();LOCAL VOID pnwatchdog ();LOCAL VOID pnrint ();LOCAL VOID pnoutput ();LOCAL VOID pnioctl ();LOCAL VOID pnsetaddr ();LOCAL VOID pnrcsrintr ();LOCAL VOID pntcsrintr ();LOCAL struct mbuf *emptyrbuf ();/********************************************************************************* pnattach -** Interface exists: make available by filling in network interface record.* System will initialize the interface when it is ready to accept packets.** RETURNS: OK or ERROR*/STATUS pnattach (unit, addr, ivec, ilevel) int unit; FAST struct pn_regs *addr; int ivec; int ilevel; { FAST struct pn_softc *vs = &pn_softc[unit]; if (pnprobe (addr) == 0) return (ERROR); vs->pnIntLevel = ilevel; vs->pn_regs = addr; addr->pn_ctl.rdmaint = (unsigned short) ((ivec+0) & 0xff); addr->pn_ctl.tdmaint_nxm = (unsigned short) ((ivec+1) & 0xff); addr->pn_ctl.rcsrint = (unsigned short) ((ivec+2) & 0xff); addr->pn_ctl.tcsrint = (unsigned short) ((ivec+3) & 0xff); addr->pn_ctl.dma_int = (unsigned short) 0; (void) intConnect (INUM_TO_IVEC (ivec+2), pnrcsrintr, unit); (void) intConnect (INUM_TO_IVEC (ivec+3), pntcsrintr, unit); sysIntEnable (ilevel); vs->vs_if.if_unit = unit; vs->vs_if.if_name = "pn"; vs->vs_if.if_mtu = PNMTU; vs->vs_if.if_init = pninit; vs->vs_if.if_ioctl = pnioctl; vs->vs_if.if_output = pnoutput; vs->vs_if.if_reset = pnreset; vs->vs_if.if_timer = 0; vs->vs_if.if_watchdog = pnwatchdog; vs->vs_if.if_flags = IFF_BROADCAST; if_attach (&vs->vs_if); return (OK); }/********************************************************************************* pnprobe - probe for presence of hardware** RETURNS: 0 if no device, otherwise non-zero*/LOCAL int pnprobe (reg) caddr_t reg; { int dummy; FAST struct pn_regs *addr = (struct pn_regs *)reg; int rcsrLen = sizeof (addr->pn_ctl.rcsr); int tcsrLen = sizeof (addr->pn_ctl.tcsr); if (vxMemProbe ((char *)&addr->pn_ctl.rcsr, READ, rcsrLen, (char *)&dummy) == ERROR || vxMemProbe ((char *)&addr->pn_ctl.tcsr, READ, tcsrLen, (char *)&dummy) == ERROR) { return (0); } /* reset interface, enable, and wait till dust settles */ /* should try to stay in ring */ if (addr->pn_ctl.rcsr & PN_JNR) addr->pn_ctl.rcsr = PN_RST | PN_JNR; else addr->pn_ctl.rcsr = PN_RST; addr->pn_ctl.tcsr = PN_RST; taskDelay (10); return (sizeof (struct pn_regs)); }/********************************************************************************* pnreset - reset of interface*/LOCAL VOID pnreset (unit) int unit; { FAST struct pn_softc *vs = &pn_softc[unit]; FAST struct pn_regs *addr = vs->pn_regs; pninit (unit); /* XXX need to? vs->vs_if.if_flags &= ~IFF_RUNNING; */ /* disable interrupts */ sysIntDisable (vs->pnIntLevel); /* set interface to known state (not interrupting) */ /* should try to stay in ring */ if (addr->pn_ctl.rcsr & PN_JNR) addr->pn_ctl.rcsr = PN_RST | PN_JNR; else addr->pn_ctl.rcsr = PN_RST; addr->pn_ctl.tcsr = PN_RST; taskDelay (10); }/********************************************************************************* pninit -** Initialization of interface; clear recorded pending* operations, and start any pending writes.*/LOCAL VOID pninit (unit) int unit; { FAST int s; FAST struct pn_softc *vs = &pn_softc[unit]; FAST struct pn_regs *addr = vs->pn_regs; if (vs->vs_tbuf == (caddr_t) 0 && (vs->vs_tbuf = (caddr_t) malloc ((unsigned) PNBUFSIZE)) == (caddr_t) 0) { logMsg ("pninit: out of memory!"); return; } /* Now that the buffers and mapping are set, * figure out our address and complete out host address; * pnidentify () will do a self-test. */ if (pnidentify (unit, 1) == 0) { vs->vs_if.if_flags &= ~IFF_UP; free((char *)vs->vs_tbuf); vs->vs_tbuf = (caddr_t) 0; return; } /* Reset the interface, and stay in the ring */ addr->pn_ctl.tcsr = PN_RST; /* reset xmt */ addr->pn_ctl.rcsr = PN_RST | PN_JNR | PN_MEN; /* reset rcv */ taskDelay (60); vs->vs_init = 0; /* clear counters */ vs->vs_refused = 0; vs->vs_timeouts = 0; vs->vs_otimeout = 0; vs->vs_ibadf = 0; vs->vs_parity = 0; /* hang receive, start any pending writes by faking a transmit complete */ s = splimp (); vs->rcvhd = 0; /* RCOUNTER starts at 0 */ addr->pn_ctl.rcsr = PN_IEN | PN_JNR | PN_MEN | PN_CEN; vs->vs_oactive = 1; vs->vs_if.if_flags |= IFF_UP | IFF_RUNNING; pnxint (unit); splx (s); }/********************************************************************************* pnidentify -** Do a moderately thorough self-test in all three modes.* Mostly to keep defective nodes off the ring than to be especially thorough.** RETURNS: host address, or 0 if error*/LOCAL int pnidentify (unit, flg) int unit; int flg; { FAST struct pn_header *v; FAST int ix; FAST int successes; FAST int failures; u_short shost = 0; u_short t_strt; /* t_strt is start of TBUFAD, and refers to lwords */ u_short *msg; u_short *msgStart; u_short pktsz; int test; BOOL ignorexmt = TRUE; FAST struct pn_softc *vs = &pn_softc[unit]; FAST struct pn_regs *addr = vs->pn_regs; t_strt = (TBUFSIZE - ((sizeof(struct pn_header) + 3) >> 2)) & 0x3ff; if ((msgStart = (u_short *) malloc (PNBUFSIZE)) == NULL) { logMsg ("pnidentify: out of memory!\n"); return (0); } /* Build a multicast address to identify our address. * We need do this only once, since nobody else is about to use * the intermediate transmit buffer (vs->vs_tbuf) that * we snagged in pninit(). */ addr->pn_ctl.tbufad = t_strt; /* reset tbufad to 0? */ v = (struct pn_header *)(vs->vs_tbuf); v->vh_dhost = PN_BROADCAST; /* multicast destination address */ v->vh_shost = 0; /* will be overwritten with ours */ v->vh_version = RING_VERSION; v->vh_type = RING_DIAGNOSTICS; v->vh_info = 0; vs->vs_olen = (sizeof(struct pn_header) + 1) >> 1; /* For each of the modes (digital, analog, network), go through * a self-test that requires me to send PNIDENTSUCC good packets * in PNIDENTRETRY attempts. Use broadcast destination to find out * who I am, then use this as my address to check my address match * logic. Only data checked is the vh_type field. */ ix = (addr->pn_ctl.rcsr & PN_JNR) == PN_JNR ? 2 : 0; for (; ix < 4; ix++) { successes = 0; /* clear successes for this mode */ failures = 0; /* and clear failures, too */ /* take over device, and leave ring */ addr->pn_ctl.tcsr = PN_RST; test = (ix < 2) ? ix : 2; addr->pn_ctl.rcsr = pn_modes[test]; /* test mode */ /* retry loop */ while (successes < PNIDENTSUCC && failures < PNIDENTRETRY) { /* cancel any previous unfinished operations */ addr->pn_ctl.rcsr = PN_RST|pn_modes[test]; addr->pn_ctl.tcsr = PN_RST; taskDelay (1); /* let's give it a little more time */ /* start a receive */ addr->pn_ctl.rcounter = 0; /* RCNTR after rcv is pkt size */ addr->pn_ctl.rcsr = pn_modes[test]|PN_CEN; /* do it */ /* send our output packet: * set up TCSR, TBUFAD, and TBUFDA's */ addr->pn_ctl.tbufad = t_strt; msg = (u_short *)vs->vs_tbuf; while ((addr->pn_ctl.tbufad & 0x7ff) != TBUFSIZE) { addr->pn_ctl.tbufda = *msg++; addr->pn_ctl.tbufda = *msg++; } addr->pn_ctl.tbufad = t_strt; addr->pn_ctl.tcsr = PN_INI|PN_ORI; taskDelay (1); /* wait to receive message */ if ((addr->pn_ctl.rcsr & PN_RDY) == 0 || (addr->pn_ctl.tcsr & PN_RDY) == 0) { failures++; continue; } /* check csr status on this packet */ if ((addr->pn_ctl.rstatr & PNRERR) || (addr->pn_ctl.tcsr & PNTERR)) { failures++; continue; } if (ignorexmt && test == 0) { /* Ignore the first xmit message.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -