📄 if_xdssonic.c
字号:
/* $Id: if_xdssonic.c,v 1.5 1998/12/28 14:13:00 nigel Exp $ *//* * if_sonic.c: National Semiconductor SONIC Driver * * Copyright (c) 1992 ALGORITHMICS LIMITED * ALL RIGHTS RESERVED * * THIS SOFTWARE PRODUCT CONTAINS THE UNPUBLISHED SOURCE * CODE OF ALGORITHMICS LIMITED * * The copyright notices above do not evidence any actual * or intended publication of such source code. * */#define DEBUG#ifndef INET#define INET#endif#include "sys/param.h"#include "sys/systm.h"#include "sys/mbuf.h"#include "sys/protosw.h"#include "sys/socket.h"#include "sys/errno.h"#include "sys/uio.h"#include "sys/ioctl.h"#include "sys/syslog.h"#include "net/if.h"#include "net/if_types.h"#include "net/netisr.h"#include "net/route.h"#ifdef INET#include "netinet/in.h"#include "netinet/in_systm.h"#include "netinet/in_var.h"#include "netinet/ip.h"#include "netinet/if_ether.h"#endif#include "mips.h"#include "sbd.h"#include "if_sonic.h"#define NSONIC 1 /* number of sonics */#define TINYFRAG 12 /* tx frags < this size count as "tiny" */#define MAXTINIES 3 /* max "tiny" frags, after which we compress */#define SNRETRIES 5 /* max retries on fatal tx errors */#define DBG_TXPKT 0x02#define DBG_RXPKT 0x04int T_sn = 0;#define T_txp (T_sn & DBG_TXPKT)#define T_rxp (T_sn & DBG_RXPKT)#ifdef R4000#ifdef XDS#define clean_dcache mips_clean_dcache#else#define clean_dcache mips_clean_dcache#endif#else#define clean_dcache r3k_dclean#endif#define MASK(x) ((x) & 0xffff)/* * Statistics collected over time * (same order as enpstats) */struct sn_stats { int ss_tpacks; /* transmit ok */ int ss_tmore; /* transmit more than one retry */ int ss_tone; /* transmit one retry */ int ss_cerr; /* transmit failed after retries */ int ss_tdef; /* transmit deferred */ int ss_tbuff; /* transmit buffer errors */ int ss_tuflo; /* transmit silo underflow */ int ss_tlcol; /* transmit late collisions */ int ss_tlcar; /* transmit lost carriers */ int ss_babl; /* transmit babbling */ int ss_noheart; /* transmit no heartbeat */ int ss_tmerr; /* transmit memory error */ int ss_rpacks; /* receive ok */ int ss_miss; /* receive missed packets */ int ss_rcrc; /* receive crc errors */ int ss_rfram; /* receive framing errors */ int ss_rbuff; /* receive buffer errors */ int ss_roflo; /* receive silo overflow */ int ss_rmerr; /* receive memory error */};static struct sn_softc { struct arpcom sn_ac;#define sn_if sn_ac.ac_if /* network visible interface */#define sn_enaddr sn_ac.ac_enaddr /* hardware ethernet address */ volatile struct sn_reg *sn_csr; /* hardware pointer */ int sn_rxmark; /* index in rx ring */ int sn_rramark; /* index into rra of wp */ volatile struct RXpkt *sn_lrxp; /* last RDA available to chip */ int sn_retries; /* transmit retries */ int sn_rbe; /* had an RBE signal */ struct sn_stats sn_sum; /* software maintained stats */ u_int sn_crct; /* crc tally from chip */ u_int sn_faet; /* frame error tally from chip */ u_int sn_mpt; /* missed packet tally from chip */ int sn_rev; /* chip revision number */} sn_softc[NSONIC];/* Public functions from outside this module */static int snifinit (int unit);static int snioctl (struct ifnet *ifp, int cmd, caddr_t data);static int snifstart (struct ifnet *ifp);static int snwatch (int unit);static int snreset (int unit);static void snintr (int unit);/* Local functions */static int snrestart (struct sn_softc *sn);static int snstartup (struct sn_softc *sn);static int snclosedown (struct sn_softc *sn);static int snput (struct sn_softc *sn, struct mbuf *m0);static void sntxint (struct sn_softc *);static void sntxdump (volatile struct TXpkt *txp);static void snrxint (struct sn_softc *);static int snerrint (struct sn_softc *, u_int isr);static struct mbuf *snget (struct sn_softc *sn, caddr_t addr, int dlen, int toff, int tlen);static int snread (struct sn_softc *, volatile struct RXpkt *);static struct mbuf *sn_fillup (struct mbuf *m0, int minlen);static void caminitialise (void);static void camentry (int, u_char *ea);static int camprogram (struct sn_softc *);static int allocatebuffers (void);static void initialise_tda (struct sn_softc *);static void initialise_rda (struct sn_softc *);static void initialise_rra (struct sn_softc *);#ifdef MIPSELstatic void snswapb (u_char *s, u_char *d, int len);static struct mbuf *snswapm (struct mbuf *m);#endifstatic void copy_data_to_host (caddr_t sp, caddr_t dp, int len);static void copy_host_to_data (caddr_t sp, caddr_t dp, int len);static void xds_compress_buffer (caddr_t addr, int len);static void xds_expand_buffer (caddr_t addr, int len);static void sonictxdump (char *msg, struct TXpkt *txp);static void sonicdump (char *msg, volatile struct sn_reg *csr);#if defined(XDSSONICBUG)/* * SONIC buffers need to be aligned 64 bit aligned. * These macros calculate and verify alignment. */#define SONICDW 64#define SONICALIGN (SONICDW/16)#else/* * SONIC buffers need to be aligned 16 or 32 bit aligned. * These macros calculate and verify alignment. */#define SONICDW 32#define SONICALIGN (SONICDW/8)#endif#ifdef XDSSONICBUG#define UPPER(x) (K0_TO_PHYS((x)) >> 17)#define LOWER(x) ((((unsigned int)(x)) >> 1) & 0xffff)#else#define UPPER(x) (K0_TO_PHYS((x)) >> 16)#define LOWER(x) (((unsigned int)(x)) & 0xffff)#endif/* * buffer sizes in 32 bit mode * 1 TXpkt is 4 hdr words + (3 * FRAGMAX) + 1 link word * FRAGMAX == 16 => 54 words == 216 bytes * * 1 RxPkt is 7 words == 28 bytes * 1 Rda is 4 words == 16 bytes */#define NRRA 32 /* # receive resource descriptors */#define RRAMASK (NRRA-1) /* why it must be power of two */#define NRBA 16 /* # receive buffers < NRRA */#define NRDA NRBA /* # receive descriptors */#define NTDA 4 /* # transmit descriptors */#define CDASIZE sizeof(struct CDA)#define RRASIZE (NRRA*sizeof(struct RXrsrc))#define RDASIZE (NRDA*sizeof(struct RXpkt))#define TDASIZE (NTDA*sizeof(struct TXpkt))/* size of FCS (CRC) appended to received packets */#define FCSSIZE 4 /* buffer size (enough for 1 max packet 1520 up to cache line boundary) */#ifdef XDSSONICBUG#define RBASIZE (1536*2)#else#define RBASIZE 1536#endif#ifdef XDS/* * transmit data must be copied into SRAM */#define TBASIZE RBASIZE#endif/* eobc set for only one packet per buffer */#define EOBC 1520 /* Assumes 32 bit operation *//* total buffer size needed for all descriptors */#define SONICBUFSIZE ((RRASIZE+CDASIZE+RDASIZE+TDASIZE)*2 + SONICALIGN - 1)/* * aligned pointers into sonic buffers */static volatile struct RXrsrc *rra; /* receiver resource descriptors */static volatile struct RXpkt *rda; /* receiver desriptors */static volatile struct TXpkt *tda; /* transmitter descriptors */static volatile struct CDA *cda; /* CAM descriptors *//* * receive buffers for sonic accessed by SONIC * each buffer will hold one ethernet packet */static char *rba;#ifdef XDSstatic char *tba;#endif/* Meta transmit descriptors */static struct mtd { struct mtd *mtd_link; volatile struct TXpkt *mtd_txp; struct mbuf *mtd_mbuf;#ifdef XDS char *mtd_tba;#endif} mtda[NTDA];static struct mtd *mtdfree; /* list of free meta transmit descriptors */static struct mtd *mtdhead; /* head of descriptors assigned to chip */static struct mtd *mtdtail; /* tail of descriptors assigned to chip */static struct mtd *mtdnext; /* next descriptor to give to chip */static struct mtd *mtd_alloc (void);static void mtd_free (struct mtd *);static void sntxdone (struct sn_softc *, struct mtd *);/* * eninit(): initialise ethernet * check to see if sonic chip is on the machine */inteninit (){ int unit = 0; struct sn_softc *sn = &sn_softc[unit]; struct ifnet *ifp = &sn->sn_if; volatile struct sn_reg *csr; int timeout; u_short dcr; csr = (struct sn_reg *) PHYS_TO_K1 (SONIC_BASE); log (LOG_DEBUG, "eninit starting\n"); /* reset Sonic chip */#if defined(XDS) *(u_int *) PHYS_TO_K1 (VME_SONIC_RES) = RESET_ACTIVE; wbflush (); DELAY(1000); *(u_int *) PHYS_TO_K1 (VME_SONIC_RES) = RESET_INACTIVE; wbflush ();#elif defined(P4000) *(u_int *) PHYS_TO_K1 (NET_RESET_) = RESET_ZERO; wbflush(); DELAY(1000); *(u_int *) PHYS_TO_K1 (NET_RESET_) = RESET_ONE; wbflush();#else /* other Algorithmics boards */ *(u_int *) PHYS_TO_K1 (BCRR) &= ~BCRR_ETH; wbflush(); DELAY(1000); *(u_int *) PHYS_TO_K1 (BCRR) |= BCRR_ETH; wbflush();#endif DELAY(1000); if (!(csr->s_cr & CR_RST)) { log (LOG_ERR, "sonic: did not reset\n"); return; } /* config it */ dcr = DCR_ASYNC|DCR_WAIT0|DCR_DW32|DCR_DMABLOCK|DCR_RFT24|DCR_TFT24; csr->s_dcr = dcr; wbflush(); if ((csr->s_dcr & ~(DCR_USR1|DCR_USR0)) != dcr) { log (LOG_ERR, "sonic: cannot configure\n"); return; } csr->s_imr = 0; wbflush(); sn->sn_rev = csr->s_sr; ifp = &sn->sn_if; ifp->if_name = "en"; ifp->if_unit = unit; if (sbdethaddr (sn->sn_enaddr) < 0) { return; } log (LOG_INFO, "%s%d: rev %d, ethernet address: %s\n", sn->sn_if.if_name, sn->sn_if.if_unit, sn->sn_rev, ether_sprintf (sn->sn_enaddr)); /* network management */ ifp->if_type = IFT_ETHER; ifp->if_addrlen = 6; ifp->if_hdrlen = 14; ifp->if_mtu = ETHERMTU; ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;#ifdef DEBUG ifp->if_flags |= IFF_DEBUG;#endif ifp->if_init = snifinit; ifp->if_output = ether_output; ifp->if_start = snifstart; ifp->if_ioctl = snioctl; ifp->if_watchdog = snwatch; ifp->if_reset = snreset; ifp->if_timer = 0; sn->sn_csr = csr; if_attach (ifp);#ifdef PROM if_newaddr(ifp, IFT_ETHER, (caddr_t)((struct arpcom *)ifp)->ac_enaddr);#else#if defined(P4000) && defined(USEINTS) sbd_setvec (CR_HINT0, IRR(0,IRR0_NET), snintr, unit);#endif log (LOG_DEBUG, "eninit completed\n");}/* * snifinit: initialise interface. */static intsnifinit (unit) int unit;{#ifdef notdef /* let SIOCSIFADDR/FLAGS do the job */ if (unit < NSONIC) { register struct sn_softc *sn = &sn_softc[unit]; int s = splimp (); if (snstartup (sn) == 0) sn->sn_if.if_flags |= IFF_UP; (void) splx (s); }#endif}/* * snioctl: process an ioctl request. */static intsnioctl (struct ifnet *ifp, int cmd, caddr_t data){ struct ifaddr *ifa = (struct ifaddr *)data; struct ifreq *ifr = (struct ifreq *)data; struct sn_softc *sn = &sn_softc[ifp->if_unit]; char *bp; int error = 0; int s = splimp(); switch (cmd) { case SIOCPOLL: if (ifp->if_flags & IFF_RUNNING) snintr (ifp->if_unit); break; case SIOCSIFADDR: ifp->if_flags |= IFF_UP; switch (ifa->ifa_addr->sa_family) {#ifdef INET case AF_INET: if (!(error = snstartup (sn))) { ((struct arpcom *)ifp)->ac_ipaddr = IA_SIN(ifa)->sin_addr;#ifdef PROM if (IA_SIN(ifa)->sin_addr.s_addr != INADDR_ANY && (IA_SIN(ifa)->sin_addr.s_addr >> IN_CLASSA_NSHIFT) != IN_LOOPBACKNET)#endif arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); } break;#endif INET#ifdef NS case AF_NS: { register struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); if (ns_nullhost(*ina)) ina->x_host = *(union ns_host *)(ns->ns_addr); else { /* force reset of controller for new address */ snclosedown (sn); bcopy((caddr_t)ina->x_host.c_host, (caddr_t)ns->ns_addr, sizeof(ns->ns_addr)); } error = snstartup (sn); break; }#endif default: error = snstartup (sn); break; } break; case SIOCSIFFLAGS: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP) /* UP switched on, but not RUNNING: start up interface */ error = snstartup (sn); else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING) /* UP switched off, but still RUNNING: close down interface */ snclosedown (sn); break; default: error = EINVAL; } splx (s); return (error);}static intsnreset (int unit){ struct sn_softc *sn = &sn_softc[unit]; if (sn->sn_if.if_flags & IFF_UP) snrestart (sn);}/* * snrestart(): reset and restart the SONIC * * Called in case of fatal hardware/software errors. */static intsnrestart (struct sn_softc *sn){ int isup = sn->sn_if.if_flags & IFF_UP; int error; snclosedown(sn); error = snstartup(sn); if (error == 0 && isup) { /* restart dequeing of tx packets */ sn->sn_if.if_flags |= IFF_UP; snifstart (&sn->sn_if); } return error;}static intsnstartup (struct sn_softc *sn){ volatile struct sn_reg *csr = sn->sn_csr; u_short rcr; int error, s; if (!csr) /* no such device */ return ENXIO; if (!sn->sn_if.if_addrlist) /* no addresses */ return EINVAL; if (sn->sn_if.if_flags & IFF_RUNNING) /* already running */ return (0); s = splhigh ();#if 0 /* unreset it */#if defined(XDS) *(u_int *) PHYS_TO_K1 (VME_SONIC_RES) = RESET_INACTIVE; wbflush ();#elif defined(P4000) *(u_int *) PHYS_TO_K1 (NET_RESET_) = RESET_ONE; wbflush();#else *(u_int *) PHYS_TO_K1 (BCRR) |= BCRR_ETH; wbflush();#endif DELAY(1000);#endif if (!(csr->s_cr & CR_RST)) { error = EIO; goto bad; } log (LOG_INFO, "%s%d: starting interface\n", sn->sn_if.if_name, sn->sn_if.if_unit); /* config it */#if defined(XDS) csr->s_dcr = DCR_ASYNC|DCR_WAIT1|DCR_DW32|DCR_RFT24|DCR_TFT16;#elif defined(P4000) csr->s_dcr = DCR_EXBUS|DCR_LBR| DCR_ASYNC|DCR_WAIT0|DCR_DW32|DCR_DMABLOCK|DCR_RFT24|DCR_TFT16;#else csr->s_dcr = DCR_ASYNC|DCR_WAIT0|DCR_DW32|DCR_DMABLOCK|DCR_RFT24|DCR_TFT16;#endif/* csr->s_dcr2 = 0;*/ wbflush (); rcr = RCR_BRD|RCR_LBNONE; if (sn->sn_if.if_flags & IFF_PROMISC) rcr |= RCR_PRO; csr->s_rcr = rcr; /* set interrupt mask */ csr->s_imr = IMR_BREN | IMR_PTXEN | IMR_TXEREN | IMR_HBLEN | IMR_PRXEN | IMR_RDEEN | IMR_RBAEEN | IMR_RFOEN | IMR_CRCEN | IMR_FAEEN | IMR_MPEN;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -