📄 ether83815.c
字号:
/* * National Semiconductor DP83815 * * Supports only internal PHY and has been tested on: * Netgear FA311TX (using Netgear DS108 10/100 hub) * SiS 900 (works under light load only) * To do: * check Ethernet address; * test autonegotiation on 10 Mbit, and 100 Mbit full duplex; * external PHY via MII (should be common code for MII); * thresholds; * ring sizing; * physical link changes/disconnect; * push initialisation back to attach. * * C H Forsyth, forsyth@vitanuova.com, 18th June 2001. */#ifdef FS#include "all.h"#include "io.h"#include "mem.h"#include "../ip/ip.h"#else /* FS */#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "io.h"#include "../port/error.h"#include "../port/netif.h"#endif /* FS */#include "etherif.h"#include "compat.h"#define DEBUG (0)#define debug if(DEBUG)printenum { Nrde = 64, Ntde = 64,};#define Rbsz ROUNDUP(sizeof(Etherpkt)+4, 4)typedef struct Des { ulong next; int cmdsts; ulong addr; Block* bp;} Des;enum { /* cmdsts */ Own = 1<<31, /* set by data producer to hand to consumer */ More = 1<<30, /* more of packet in next descriptor */ Intr = 1<<29, /* interrupt when device is done with it */ Supcrc = 1<<28, /* suppress crc on transmit */ Inccrc = 1<<28, /* crc included on receive (always) */ Ok = 1<<27, /* packet ok */ Size = 0xFFF, /* packet size in bytes */ /* transmit */ Txa = 1<<26, /* transmission aborted */ Tfu = 1<<25, /* transmit fifo underrun */ Crs = 1<<24, /* carrier sense lost */ Td = 1<<23, /* transmission deferred */ Ed = 1<<22, /* excessive deferral */ Owc = 1<<21, /* out of window collision */ Ec = 1<<20, /* excessive collisions */ /* 19-16 collision count */ /* receive */ Rxa = 1<<26, /* receive aborted (same as Rxo) */ Rxo = 1<<25, /* receive overrun */ Dest = 3<<23, /* destination class */ Drej= 0<<23, /* packet was rejected */ Duni= 1<<23, /* unicast */ Dmulti= 2<<23, /* multicast */ Dbroad= 3<<23, /* broadcast */ Long = 1<<22, /* too long packet received */ Runt = 1<<21, /* packet less than 64 bytes */ Ise = 1<<20, /* invalid symbol */ Crce = 1<<19, /* invalid crc */ Fae = 1<<18, /* frame alignment error */ Lbp = 1<<17, /* loopback packet */ Col = 1<<16, /* collision during receive */};enum { /* PCI vendor & device IDs */ Nat83815 = (0x0020<<16)|0x100B, SiS = 0x1039, SiS900 = (0x0900<<16)|SiS, SiS7016 = (0x7016<<16)|SiS, SiS630bridge = 0x0008, /* SiS 900 PCI revision codes */ SiSrev630s = 0x81, SiSrev630e = 0x82, SiSrev630ea1 = 0x83, SiSeenodeaddr = 8, /* short addr of SiS eeprom mac addr */ SiS630eenodeaddr = 9, /* likewise for the 630 */ Nseenodeaddr = 6, /* " for NS eeprom */};typedef struct Ctlr Ctlr;typedef struct Ctlr { int port; Pcidev* pcidev; Ctlr* next; int active; int id; /* (pcidev->did<<16)|pcidev->vid */ ushort srom[0xB+1]; uchar sromea[Eaddrlen]; /* MAC address */ uchar fd; /* option or auto negotiation */ int mbps; Lock lock; Des* rdr; /* receive descriptor ring */ int nrdr; /* size of rdr */ int rdrx; /* index into rdr */ Lock tlock; Des* tdr; /* transmit descriptor ring */ int ntdr; /* size of tdr */ int tdrh; /* host index into tdr */ int tdri; /* interface index into tdr */ int ntq; /* descriptors active */ int ntqmax; ulong rxa; /* receive statistics */ ulong rxo; ulong rlong; ulong runt; ulong ise; ulong crce; ulong fae; ulong lbp; ulong col; ulong rxsovr; ulong rxorn; ulong txa; /* transmit statistics */ ulong tfu; ulong crs; ulong td; ulong ed; ulong owc; ulong ec; ulong txurn; ulong dperr; /* system errors */ ulong rmabt; ulong rtabt; ulong sserr; ulong rxsover;} Ctlr;static Ctlr* ctlrhead;static Ctlr* ctlrtail;enum { /* registers (could memory map) */ Rcr= 0x00, /* command register */ Rst= 1<<8, Rxr= 1<<5, /* receiver reset */ Txr= 1<<4, /* transmitter reset */ Rxd= 1<<3, /* receiver disable */ Rxe= 1<<2, /* receiver enable */ Txd= 1<<1, /* transmitter disable */ Txe= 1<<0, /* transmitter enable */ Rcfg= 0x04, /* configuration */ Lnksts= 1<<31, /* link good */ Speed100= 1<<30, /* 100 Mb/s link */ Fdup= 1<<29, /* full duplex */ Pol= 1<<28, /* polarity reversal (10baseT) */ Aneg_dn= 1<<27, /* autonegotiation done */ Pint_acen= 1<<17, /* PHY interrupt auto clear enable */ Pause_adv= 1<<16, /* advertise pause during auto neg */ Paneg_ena= 1<<13, /* auto negotiation enable */ Paneg_all= 7<<13, /* auto negotiation enable 10/100 half & full */ Ext_phy= 1<<12, /* enable MII for external PHY */ Phy_rst= 1<<10, /* reset internal PHY */ Phy_dis= 1<<9, /* disable internal PHY (eg, low power) */ Req_alg= 1<<7, /* PCI bus request: set means less aggressive */ Sb= 1<<6, /* single slot back-off not random */ Pow= 1<<5, /* out of window timer selection */ Exd= 1<<4, /* disable excessive deferral timer */ Pesel= 1<<3, /* parity error algorithm selection */ Brom_dis= 1<<2, /* disable boot rom interface */ Bem= 1<<0, /* big-endian mode */ Rmear= 0x08, /* eeprom access */ Mdc= 1<<6, /* MII mangement check */ Mddir= 1<<5, /* MII management direction */ Mdio= 1<<4, /* MII mangement data */ Eesel= 1<<3, /* EEPROM chip select */ Eeclk= 1<<2, /* EEPROM clock */ Eedo= 1<<1, /* EEPROM data out (from chip) */ Eedi= 1<<0, /* EEPROM data in (to chip) */ Rptscr= 0x0C, /* pci test control */ Risr= 0x10, /* interrupt status */ Txrcmp= 1<<25, /* transmit reset complete */ Rxrcmp= 1<<24, /* receiver reset complete */ Dperr= 1<<23, /* detected parity error */ Sserr= 1<<22, /* signalled system error */ Rmabt= 1<<21, /* received master abort */ Rtabt= 1<<20, /* received target abort */ Rxsovr= 1<<16, /* RX status FIFO overrun */ Hiberr= 1<<15, /* high bits error set (OR of 25-16) */ Phy= 1<<14, /* PHY interrupt */ Pme= 1<<13, /* power management event (wake online) */ Swi= 1<<12, /* software interrupt */ Mib= 1<<11, /* MIB service */ Txurn= 1<<10, /* TX underrun */ Txidle= 1<<9, /* TX idle */ Txerr= 1<<8, /* TX packet error */ Txdesc= 1<<7, /* TX descriptor (with Intr bit done) */ Txok= 1<<6, /* TX ok */ Rxorn= 1<<5, /* RX overrun */ Rxidle= 1<<4, /* RX idle */ Rxearly= 1<<3, /* RX early threshold */ Rxerr= 1<<2, /* RX packet error */ Rxdesc= 1<<1, /* RX descriptor (with Intr bit done) */ Rxok= 1<<0, /* RX ok */ Rimr= 0x14, /* interrupt mask */ Rier= 0x18, /* interrupt enable */ Ie= 1<<0, /* interrupt enable */ Rtxdp= 0x20, /* transmit descriptor pointer */ Rtxcfg= 0x24, /* transmit configuration */ Csi= 1<<31, /* carrier sense ignore (needed for full duplex) */ Hbi= 1<<30, /* heartbeat ignore (needed for full duplex) */ Atp= 1<<28, /* automatic padding of runt packets */ Mxdma= 7<<20, /* maximum dma transfer field */ Mxdma32= 4<<20, /* 4x32-bit words (32 bytes) */ Mxdma64= 5<<20, /* 8x32-bit words (64 bytes) */ Flth= 0x3F<<8,/* Tx fill threshold, units of 32 bytes (must be > Mxdma) */ Drth= 0x3F<<0,/* Tx drain threshold (units of 32 bytes) */ Flth128= 4<<8, /* fill at 128 bytes */ /* seems to be the same on SiS 900; maybe use larger value @ 100Mb/s */ Drth512= 16<<0, /* drain at 512 bytes */ Rrxdp= 0x30, /* receive descriptor pointer */ Rrxcfg= 0x34, /* receive configuration */ Atx= 1<<28, /* accept transmit packets (needed for full duplex) */ Rdrth= 0x1F<<1,/* Rx drain threshold (units of 32 bytes) */ Rdrth64= 2<<1, /* drain at 64 bytes */ Rccsr= 0x3C, /* CLKRUN control/status */ Pmests= 1<<15, /* PME status */ Rwcsr= 0x40, /* wake on lan control/status */ Rpcr= 0x44, /* pause control/status */ /* TODO: different on SiS, but does it matter? Rfen - Aau are same. */ Rrfcr= 0x48, /* receive filter/match control */ Rfen= 1<<31, /* receive filter enable */ Aab= 1<<30, /* accept all broadcast */ Aam= 1<<29, /* accept all multicast */ Aau= 1<<28, /* accept all unicast */ Apm= 1<<27, /* accept on perfect match */ Apat= 0xF<<23,/* accept on pattern match */ Aarp= 1<<22, /* accept ARP */ Mhen= 1<<21, /* multicast hash enable */ Uhen= 1<<20, /* unicast hash enable */ Ulm= 1<<19, /* U/L bit mask */ /* bits 0-9 are rfaddr */ Rrfdr= 0x4C, /* receive filter/match data */ Rbrar= 0x50, /* boot rom address */ Rbrdr= 0x54, /* boot rom data */ Rsrr= 0x58, /* silicon revision */ Rmibc= 0x5C, /* MIB control */ /* 60-78 MIB data */ /* PHY registers */ Rbmcr= 0x80, /* basic mode configuration */ Reset= 1<<15, Sel100= 1<<13, /* select 100Mb/sec if no auto neg */ Anena= 1<<12, /* auto negotiation enable */ Anrestart= 1<<9, /* restart auto negotiation */ Selfdx= 1<<8, /* select full duplex if no auto neg */ Rbmsr= 0x84, /* basic mode status */ Ancomp= 1<<5, /* autonegotiation complete */ Rphyidr1= 0x88, Rphyidr2= 0x8C, Ranar= 0x90, /* autonegotiation advertisement */ Ranlpar= 0x94, /* autonegotiation link partner ability */ Raner= 0x98, /* autonegotiation expansion */ Rannptr= 0x9C, /* autonegotiation next page TX */ Rphysts= 0xC0, /* PHY status */ Rmicr= 0xC4, /* MII control */ Inten= 1<<1, /* PHY interrupt enable */ Rmisr= 0xC8, /* MII status */ Rfcscr= 0xD0, /* false carrier sense counter */ Rrecr= 0xD4, /* receive error counter */ Rpcsr= 0xD8, /* 100Mb config/status */ Rphycr= 0xE4, /* PHY control */ Rtbscr= 0xE8, /* 10BaseT status/control */};/* * eeprom addresses * 7 to 9 (16 bit words): mac address, shifted and reversed */#define csr32r(c, r) (inl((c)->port+(r)))#define csr32w(c, r, l) (outl((c)->port+(r), (ulong)(l)))#define csr16r(c, r) (ins((c)->port+(r)))#define csr16w(c, r, l) (outs((c)->port+(r), (ulong)(l)))static voiddumpcregs(Ctlr *ctlr){ int i; for(i=0; i<=0x5C; i+=4) print("%2.2ux %8.8lux\n", i, csr32r(ctlr, i));}static voidpromiscuous(void* arg, int on){ Ctlr *ctlr; ulong w; ctlr = ((Ether*)arg)->ctlr; ilock(&ctlr->lock); w = csr32r(ctlr, Rrfcr); if(on != ((w&Aau)!=0)){ csr32w(ctlr, Rrfcr, w & ~Rfen); csr32w(ctlr, Rrfcr, Rfen | (w ^ Aau)); } iunlock(&ctlr->lock);}static voidattach(Ether* ether){ Ctlr *ctlr; ctlr = ether->ctlr; ilock(&ctlr->lock); if(0) dumpcregs(ctlr); csr32w(ctlr, Rcr, Rxe); iunlock(&ctlr->lock);}#ifndef FSstatic longifstat(Ether* ether, void* a, long n, ulong offset){ Ctlr *ctlr; char *buf, *p; int i, l, len; ctlr = ether->ctlr; ether->crcs = ctlr->crce; ether->frames = ctlr->runt+ctlr->ise+ctlr->rlong+ctlr->fae; ether->buffs = ctlr->rxorn+ctlr->tfu; ether->overflows = ctlr->rxsovr; if(n == 0) return 0; p = malloc(READSTR); l = snprint(p, READSTR, "Rxa: %lud\n", ctlr->rxa); l += snprint(p+l, READSTR-l, "Rxo: %lud\n", ctlr->rxo); l += snprint(p+l, READSTR-l, "Rlong: %lud\n", ctlr->rlong); l += snprint(p+l, READSTR-l, "Runt: %lud\n", ctlr->runt); l += snprint(p+l, READSTR-l, "Ise: %lud\n", ctlr->ise); l += snprint(p+l, READSTR-l, "Fae: %lud\n", ctlr->fae); l += snprint(p+l, READSTR-l, "Lbp: %lud\n", ctlr->lbp); l += snprint(p+l, READSTR-l, "Tfu: %lud\n", ctlr->tfu); l += snprint(p+l, READSTR-l, "Txa: %lud\n", ctlr->txa); l += snprint(p+l, READSTR-l, "CRC Error: %lud\n", ctlr->crce); l += snprint(p+l, READSTR-l, "Collision Seen: %lud\n", ctlr->col); l += snprint(p+l, READSTR-l, "Frame Too Long: %lud\n", ctlr->rlong); l += snprint(p+l, READSTR-l, "Runt Frame: %lud\n", ctlr->runt); l += snprint(p+l, READSTR-l, "Rx Underflow Error: %lud\n", ctlr->rxorn); l += snprint(p+l, READSTR-l, "Tx Underrun: %lud\n", ctlr->txurn); l += snprint(p+l, READSTR-l, "Excessive Collisions: %lud\n", ctlr->ec); l += snprint(p+l, READSTR-l, "Late Collision: %lud\n", ctlr->owc); l += snprint(p+l, READSTR-l, "Loss of Carrier: %lud\n", ctlr->crs); l += snprint(p+l, READSTR-l, "Parity: %lud\n", ctlr->dperr); l += snprint(p+l, READSTR-l, "Aborts: %lud\n", ctlr->rmabt+ctlr->rtabt); l += snprint(p+l, READSTR-l, "RX Status overrun: %lud\n", ctlr->rxsover); snprint(p+l, READSTR-l, "ntqmax: %d\n", ctlr->ntqmax); ctlr->ntqmax = 0; buf = a; len = readstr(offset, buf, n, p); if(offset > l) offset -= l; else offset = 0; buf += len; n -= len; l = snprint(p, READSTR, "srom:"); for(i = 0; i < nelem(ctlr->srom); i++){ if(i && ((i & 0x0F) == 0)) l += snprint(p+l, READSTR-l, "\n "); l += snprint(p+l, READSTR-l, " %4.4uX", ctlr->srom[i]); } snprint(p+l, READSTR-l, "\n"); len += readstr(offset, buf, n, p); free(p); return len;}#endifstatic voidtxstart(Ether* ether){ Ctlr *ctlr; Block *bp; Des *des; int started; ctlr = ether->ctlr; started = 0; while(ctlr->ntq < ctlr->ntdr-1){ bp = etheroq(ether); if(bp == nil) break; des = &ctlr->tdr[ctlr->tdrh]; des->bp = bp; des->addr = PADDR(bp->rp); ctlr->ntq++; coherence(); des->cmdsts = Own | BLEN(bp); ctlr->tdrh = NEXT(ctlr->tdrh, ctlr->ntdr); started = 1; } if(started){ coherence(); csr32w(ctlr, Rcr, Txe); /* prompt */ } if(ctlr->ntq > ctlr->ntqmax) ctlr->ntqmax = ctlr->ntq;}static voidtransmit(Ether* ether){ Ctlr *ctlr; ctlr = ether->ctlr; ilock(&ctlr->tlock); txstart(ether); iunlock(&ctlr->tlock);}static voidtxrxcfg(Ctlr *ctlr, int txdrth){ ulong rx, tx; rx = csr32r(ctlr, Rrxcfg); tx = csr32r(ctlr, Rtxcfg); if(ctlr->fd){ rx |= Atx; tx |= Csi | Hbi; }else{ rx &= ~Atx; tx &= ~(Csi | Hbi); } tx &= ~(Mxdma|Drth|Flth); tx |= Mxdma64 | Flth128 | txdrth; csr32w(ctlr, Rtxcfg, tx); rx &= ~(Mxdma|Rdrth); rx |= Mxdma64 | Rdrth64; csr32w(ctlr, Rrxcfg, rx);}static voidinterrupt(Ureg*, void* arg){ Ctlr *ctlr; Ether *ether; int len, status, cmdsts; Des *des; Block *bp; ether = arg; ctlr = ether->ctlr; while((status = csr32r(ctlr, Risr)) != 0){ status &= ~(Pme|Mib); if(status & Hiberr){ if(status & Rxsovr) ctlr->rxsover++; if(status & Sserr) ctlr->sserr++; if(status & Dperr) ctlr->dperr++; if(status & Rmabt) ctlr->rmabt++; if(status & Rtabt) ctlr->rtabt++; status &= ~(Hiberr|Txrcmp|Rxrcmp|Rxsovr|Dperr|Sserr|Rmabt|Rtabt); } /* * Received packets. */ if(status & (Rxdesc|Rxok|Rxerr|Rxearly|Rxorn)){ des = &ctlr->rdr[ctlr->rdrx]; while((cmdsts = des->cmdsts) & Own){ if((cmdsts&Ok) == 0){ if(cmdsts & Rxa) ctlr->rxa++; if(cmdsts & Rxo) ctlr->rxo++; if(cmdsts & Long) ctlr->rlong++; if(cmdsts & Runt) ctlr->runt++; if(cmdsts & Ise) ctlr->ise++; if(cmdsts & Crce) ctlr->crce++; if(cmdsts & Fae) ctlr->fae++; if(cmdsts & Lbp) ctlr->lbp++; if(cmdsts & Col) ctlr->col++; } else if(bp = iallocb(Rbsz)){ len = (cmdsts&Size)-4; if(len <= 0){ debug("ns83815: packet len %d <=0\n", len); freeb(des->bp); }else{ SETWPCNT(des->bp, len); ETHERIQ(ether, des->bp, 1); } des->bp = bp; des->addr = PADDR(bp->rp); coherence(); }else{ debug("ns83815: interrupt: iallocb for input buffer failed\n"); des->bp->next = 0; } des->cmdsts = Rbsz; coherence(); ctlr->rdrx = NEXT(ctlr->rdrx, ctlr->nrdr); des = &ctlr->rdr[ctlr->rdrx]; } status &= ~(Rxdesc|Rxok|Rxerr|Rxearly|Rxorn); } /* * Check the transmit side: * check for Transmit Underflow and Adjust * the threshold upwards; * free any transmitted buffers and try to * top-up the ring. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -