12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220 |
- /*
- * National Semiconductor DP83820
- * 10/100/1000 Mb/s Ethernet Network Interface Controller
- * (Gig-NIC).
- * Driver assumes little-endian and 32-bit host throughout.
- */
- #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"
- #include "etherif.h"
- #include "ethermii.h"
- enum { /* Registers */
- Cr = 0x00, /* Command */
- Cfg = 0x04, /* Configuration and Media Status */
- Mear = 0x08, /* MII/EEPROM Access */
- Ptscr = 0x0C, /* PCI Test Control */
- Isr = 0x10, /* Interrupt Status */
- Imr = 0x14, /* Interrupt Mask */
- Ier = 0x18, /* Interrupt Enable */
- Ihr = 0x1C, /* Interrupt Holdoff */
- Txdp = 0x20, /* Transmit Descriptor Pointer */
- Txdphi = 0x24, /* Transmit Descriptor Pointer Hi */
- Txcfg = 0x28, /* Transmit Configuration */
- Gpior = 0x2C, /* General Purpose I/O Control */
- Rxdp = 0x30, /* Receive Descriptor Pointer */
- Rxdphi = 0x34, /* Receive Descriptor Pointer Hi */
- Rxcfg = 0x38, /* Receive Configuration */
- Pqcr = 0x3C, /* Priority Queueing Control */
- Wcsr = 0x40, /* Wake on LAN Control/Status */
- Pcr = 0x44, /* Pause Control/Status */
- Rfcr = 0x48, /* Receive Filter/Match Control */
- Rfdr = 0x4C, /* Receive Filter/Match Data */
- Brar = 0x50, /* Boot ROM Address */
- Brdr = 0x54, /* Boot ROM Data */
- Srr = 0x58, /* Silicon Revision */
- Mibc = 0x5C, /* MIB Control */
- Mibd = 0x60, /* MIB Data */
- Txdp1 = 0xA0, /* Txdp Priority 1 */
- Txdp2 = 0xA4, /* Txdp Priority 2 */
- Txdp3 = 0xA8, /* Txdp Priority 3 */
- Rxdp1 = 0xB0, /* Rxdp Priority 1 */
- Rxdp2 = 0xB4, /* Rxdp Priority 2 */
- Rxdp3 = 0xB8, /* Rxdp Priority 3 */
- Vrcr = 0xBC, /* VLAN/IP Receive Control */
- Vtcr = 0xC0, /* VLAN/IP Transmit Control */
- Vdr = 0xC4, /* VLAN Data */
- Ccsr = 0xCC, /* Clockrun Control/Status */
- Tbicr = 0xE0, /* TBI Control */
- Tbisr = 0xE4, /* TBI Status */
- Tanar = 0xE8, /* TBI ANAR */
- Tanlpar = 0xEC, /* TBI ANLPAR */
- Taner = 0xF0, /* TBI ANER */
- Tesr = 0xF4, /* TBI ESR */
- };
- enum { /* Cr */
- Txe = 0x00000001, /* Transmit Enable */
- Txd = 0x00000002, /* Transmit Disable */
- Rxe = 0x00000004, /* Receiver Enable */
- Rxd = 0x00000008, /* Receiver Disable */
- Txr = 0x00000010, /* Transmitter Reset */
- Rxr = 0x00000020, /* Receiver Reset */
- Swien = 0x00000080, /* Software Interrupt Enable */
- Rst = 0x00000100, /* Reset */
- TxpriSHFT = 9, /* Tx Priority Queue Select */
- TxpriMASK = 0x00001E00,
- RxpriSHFT = 13, /* Rx Priority Queue Select */
- RxpriMASK = 0x0001E000,
- };
- enum { /* Configuration and Media Status */
- Bem = 0x00000001, /* Big Endian Mode */
- Ext125 = 0x00000002, /* External 125MHz reference Select */
- Bromdis = 0x00000004, /* Disable Boot ROM interface */
- Pesel = 0x00000008, /* Parity Error Detection Action */
- Exd = 0x00000010, /* Excessive Deferral Abort */
- Pow = 0x00000020, /* Program Out of Window Timer */
- Sb = 0x00000040, /* Single Back-off */
- Reqalg = 0x00000080, /* PCI Bus Request Algorithm */
- Extstsen = 0x00000100, /* Extended Status Enable */
- Phydis = 0x00000200, /* Disable PHY */
- Phyrst = 0x00000400, /* Reset PHY */
- M64addren = 0x00000800, /* Master 64-bit Addressing Enable */
- Data64en = 0x00001000, /* 64-bit Data Enable */
- Pci64det = 0x00002000, /* PCI 64-bit Bus Detected */
- T64addren = 0x00004000, /* Target 64-bit Addressing Enable */
- Mwidis = 0x00008000, /* MWI Disable */
- Mrmdis = 0x00010000, /* MRM Disable */
- Tmrtest = 0x00020000, /* Timer Test Mode */
- Spdstsien = 0x00040000, /* PHY Spdsts Interrupt Enable */
- Lnkstsien = 0x00080000, /* PHY Lnksts Interrupt Enable */
- Dupstsien = 0x00100000, /* PHY Dupsts Interrupt Enable */
- Mode1000 = 0x00400000, /* 1000Mb/s Mode Control */
- Tbien = 0x01000000, /* Ten-Bit Interface Enable */
- Dupsts = 0x10000000, /* Full Duplex Status */
- Spdsts100 = 0x20000000, /* SPEED100 Input Pin Status */
- Spdsts1000 = 0x40000000, /* SPEED1000 Input Pin Status */
- Lnksts = 0x80000000, /* Link Status */
- };
- enum { /* MII/EEPROM Access */
- Eedi = 0x00000001, /* EEPROM Data In */
- Eedo = 0x00000002, /* EEPROM Data Out */
- Eeclk = 0x00000004, /* EEPROM Serial Clock */
- Eesel = 0x00000008, /* EEPROM Chip Select */
- Mdio = 0x00000010, /* MII Management Data */
- Mddir = 0x00000020, /* MII Management Direction */
- Mdc = 0x00000040, /* MII Management Clock */
- };
- enum { /* Interrupts */
- Rxok = 0x00000001, /* Rx OK */
- Rxdesc = 0x00000002, /* Rx Descriptor */
- Rxerr = 0x00000004, /* Rx Packet Error */
- Rxearly = 0x00000008, /* Rx Early Threshold */
- Rxidle = 0x00000010, /* Rx Idle */
- Rxorn = 0x00000020, /* Rx Overrun */
- Txok = 0x00000040, /* Tx Packet OK */
- Txdesc = 0x00000080, /* Tx Descriptor */
- Txerr = 0x00000100, /* Tx Packet Error */
- Txidle = 0x00000200, /* Tx Idle */
- Txurn = 0x00000400, /* Tx Underrun */
- Mib = 0x00000800, /* MIB Service */
- Swi = 0x00001000, /* Software Interrupt */
- Pme = 0x00002000, /* Power Management Event */
- Phy = 0x00004000, /* PHY Interrupt */
- Hibint = 0x00008000, /* High Bits Interrupt Set */
- Rxsovr = 0x00010000, /* Rx Status FIFO Overrun */
- Rtabt = 0x00020000, /* Received Target Abort */
- Rmabt = 0x00040000, /* Received Master Abort */
- Sserr = 0x00080000, /* Signalled System Error */
- Dperr = 0x00100000, /* Detected Parity Error */
- Rxrcmp = 0x00200000, /* Receive Reset Complete */
- Txrcmp = 0x00400000, /* Transmit Reset Complete */
- Rxdesc0 = 0x00800000, /* Rx Descriptor for Priority Queue 0 */
- Rxdesc1 = 0x01000000, /* Rx Descriptor for Priority Queue 1 */
- Rxdesc2 = 0x02000000, /* Rx Descriptor for Priority Queue 2 */
- Rxdesc3 = 0x04000000, /* Rx Descriptor for Priority Queue 3 */
- Txdesc0 = 0x08000000, /* Tx Descriptor for Priority Queue 0 */
- Txdesc1 = 0x10000000, /* Tx Descriptor for Priority Queue 1 */
- Txdesc2 = 0x20000000, /* Tx Descriptor for Priority Queue 2 */
- Txdesc3 = 0x40000000, /* Tx Descriptor for Priority Queue 3 */
- };
- enum { /* Interrupt Enable */
- Ien = 0x00000001, /* Interrupt Enable */
- };
- enum { /* Interrupt Holdoff */
- IhSHFT = 0, /* Interrupt Holdoff */
- IhMASK = 0x000000FF,
- Ihctl = 0x00000100, /* Interrupt Holdoff Control */
- };
- enum { /* Transmit Configuration */
- TxdrthSHFT = 0, /* Tx Drain Threshold */
- TxdrthMASK = 0x000000FF,
- FlthSHFT = 16, /* Tx Fill Threshold */
- FlthMASK = 0x0000FF00,
- Brstdis = 0x00080000, /* 1000Mb/s Burst Disable */
- MxdmaSHFT = 20, /* Max Size per Tx DMA Burst */
- MxdmaMASK = 0x00700000,
- Ecretryen = 0x00800000, /* Excessive Collision Retry Enable */
- Atp = 0x10000000, /* Automatic Transmit Padding */
- Mlb = 0x20000000, /* MAC Loopback */
- Hbi = 0x40000000, /* Heartbeat Ignore */
- Csi = 0x80000000, /* Carrier Sense Ignore */
- };
- enum { /* Receive Configuration */
- RxdrthSHFT = 1, /* Rx Drain Threshold */
- RxdrthMASK = 0x0000003E,
- Airl = 0x04000000, /* Accept In-Range Length Errored */
- Alp = 0x08000000, /* Accept Long Packets */
- Rxfd = 0x10000000, /* Receive Full Duplex */
- Stripcrc = 0x20000000, /* Strip CRC */
- Arp = 0x40000000, /* Accept Runt Packets */
- Aep = 0x80000000, /* Accept Errored Packets */
- };
- enum { /* Priority Queueing Control */
- Txpqen = 0x00000001, /* Transmit Priority Queuing Enable */
- Txfairen = 0x00000002, /* Transmit Fairness Enable */
- RxpqenSHFT = 2, /* Receive Priority Queue Enable */
- RxpqenMASK = 0x0000000C,
- };
- enum { /* Pause Control/Status */
- PscntSHFT = 0, /* Pause Counter Value */
- PscntMASK = 0x0000FFFF,
- Pstx = 0x00020000, /* Transmit Pause Frame */
- PsffloSHFT = 18, /* Rx Data FIFO Lo Threshold */
- PsffloMASK = 0x000C0000,
- PsffhiSHFT = 20, /* Rx Data FIFO Hi Threshold */
- PsffhiMASK = 0x00300000,
- PsstloSHFT = 22, /* Rx Stat FIFO Hi Threshold */
- PsstloMASK = 0x00C00000,
- PssthiSHFT = 24, /* Rx Stat FIFO Hi Threshold */
- PssthiMASK = 0x03000000,
- Psrcvd = 0x08000000, /* Pause Frame Received */
- Psact = 0x10000000, /* Pause Active */
- Psda = 0x20000000, /* Pause on Destination Address */
- Psmcast = 0x40000000, /* Pause on Multicast */
- Psen = 0x80000000, /* Pause Enable */
- };
- enum { /* Receive Filter/Match Control */
- RfaddrSHFT = 0, /* Extended Register Address */
- RfaddrMASK = 0x000003FF,
- Ulm = 0x00080000, /* U/L bit mask */
- Uhen = 0x00100000, /* Unicast Hash Enable */
- Mhen = 0x00200000, /* Multicast Hash Enable */
- Aarp = 0x00400000, /* Accept ARP Packets */
- ApatSHFT = 23, /* Accept on Pattern Match */
- ApatMASK = 0x07800000,
- Apm = 0x08000000, /* Accept on Perfect Match */
- Aau = 0x10000000, /* Accept All Unicast */
- Aam = 0x20000000, /* Accept All Multicast */
- Aab = 0x40000000, /* Accept All Broadcast */
- Rfen = 0x80000000, /* Rx Filter Enable */
- };
- enum { /* Receive Filter/Match Data */
- RfdataSHFT = 0, /* Receive Filter Data */
- RfdataMASK = 0x0000FFFF,
- BmaskSHFT = 16, /* Byte Mask */
- BmaskMASK = 0x00030000,
- };
- enum { /* MIB Control */
- Wrn = 0x00000001, /* Warning Test Indicator */
- Frz = 0x00000002, /* Freeze All Counters */
- Aclr = 0x00000004, /* Clear All Counters */
- Mibs = 0x00000008, /* MIB Counter Strobe */
- };
- enum { /* MIB Data */
- Nmibd = 11, /* Number of MIB Data Registers */
- };
- enum { /* VLAN/IP Receive Control */
- Vtden = 0x00000001, /* VLAN Tag Detection Enable */
- Vtren = 0x00000002, /* VLAN Tag Removal Enable */
- Dvtf = 0x00000004, /* Discard VLAN Tagged Frames */
- Dutf = 0x00000008, /* Discard Untagged Frames */
- Ipen = 0x00000010, /* IP Checksum Enable */
- Ripe = 0x00000020, /* Reject IP Checksum Errors */
- Rtcpe = 0x00000040, /* Reject TCP Checksum Errors */
- Rudpe = 0x00000080, /* Reject UDP Checksum Errors */
- };
- enum { /* VLAN/IP Transmit Control */
- Vgti = 0x00000001, /* VLAN Global Tag Insertion */
- Vppti = 0x00000002, /* VLAN Per-Packet Tag Insertion */
- Gchk = 0x00000004, /* Global Checksum Generation */
- Ppchk = 0x00000008, /* Per-Packet Checksum Generation */
- };
- enum { /* VLAN Data */
- VtypeSHFT = 0, /* VLAN Type Field */
- VtypeMASK = 0x0000FFFF,
- VtciSHFT = 16, /* VLAN Tag Control Information */
- VtciMASK = 0xFFFF0000,
- };
- enum { /* Clockrun Control/Status */
- Clkrunen = 0x00000001, /* CLKRUN Enable */
- Pmeen = 0x00000100, /* PME Enable */
- Pmests = 0x00008000, /* PME Status */
- };
- typedef struct {
- u32int link; /* Link to the next descriptor */
- u32int bufptr; /* pointer to data Buffer */
- int cmdsts; /* Command/Status */
- int extsts; /* optional Extended Status */
- Block* bp; /* Block containing bufptr */
- u32int unused; /* pad to 64-bit */
- } Desc;
- enum { /* Common cmdsts bits */
- SizeMASK = 0x0000FFFF, /* Descriptor Byte Count */
- SizeSHFT = 0,
- Ok = 0x08000000, /* Packet OK */
- Crc = 0x10000000, /* Suppress/Include CRC */
- Intr = 0x20000000, /* Interrupt on ownership transfer */
- More = 0x40000000, /* not last descriptor in a packet */
- Own = 0x80000000, /* Descriptor Ownership */
- };
- enum { /* Transmit cmdsts bits */
- CcntMASK = 0x000F0000, /* Collision Count */
- CcntSHFT = 16,
- Ec = 0x00100000, /* Excessive Collisions */
- Owc = 0x00200000, /* Out of Window Collision */
- Ed = 0x00400000, /* Excessive Deferral */
- Td = 0x00800000, /* Transmit Deferred */
- Crs = 0x01000000, /* Carrier Sense Lost */
- Tfu = 0x02000000, /* Transmit FIFO Underrun */
- Txa = 0x04000000, /* Transmit Abort */
- };
- enum { /* Receive cmdsts bits */
- Irl = 0x00010000, /* In-Range Length Error */
- Lbp = 0x00020000, /* Loopback Packet */
- Fae = 0x00040000, /* Frame Alignment Error */
- Crce = 0x00080000, /* CRC Error */
- Ise = 0x00100000, /* Invalid Symbol Error */
- Runt = 0x00200000, /* Runt Packet Received */
- Long = 0x00400000, /* Too Long Packet Received */
- DestMASK = 0x01800000, /* Destination Class */
- DestSHFT = 23,
- Rxo = 0x02000000, /* Receive Overrun */
- Rxa = 0x04000000, /* Receive Aborted */
- };
- enum { /* extsts bits */
- EvtciMASK = 0x0000FFFF, /* VLAN Tag Control Information */
- EvtciSHFT = 0,
- Vpkt = 0x00010000, /* VLAN Packet */
- Ippkt = 0x00020000, /* IP Packet */
- Iperr = 0x00040000, /* IP Checksum Error */
- Tcppkt = 0x00080000, /* TCP Packet */
- Tcperr = 0x00100000, /* TCP Checksum Error */
- Udppkt = 0x00200000, /* UDP Packet */
- Udperr = 0x00400000, /* UDP Checksum Error */
- };
- enum {
- Nrd = 256,
- Nrb = 4*Nrd,
- Rbsz = ROUNDUP(sizeof(Etherpkt)+8, 8),
- Ntd = 128,
- };
- typedef struct Ctlr Ctlr;
- typedef struct Ctlr {
- int port;
- Pcidev* pcidev;
- Ctlr* next;
- int active;
- int id;
- int eepromsz; /* address size in bits */
- ushort* eeprom;
- int* nic;
- int cfg;
- int imr;
- QLock alock; /* attach */
- Lock ilock; /* init */
- void* alloc; /* base of per-Ctlr allocated data */
- Mii* mii;
- Lock rdlock; /* receive */
- Desc* rd;
- int nrd;
- int nrb;
- int rdx;
- int rxcfg;
- Lock tlock; /* transmit */
- Desc* td;
- int ntd;
- int tdh;
- int tdt;
- int ntq;
- int txcfg;
- int rxidle;
- uint mibd[Nmibd];
- int ec;
- int owc;
- int ed;
- int crs;
- int tfu;
- int txa;
- } Ctlr;
- #define csr32r(c, r) (*((c)->nic+((r)/4)))
- #define csr32w(c, r, v) (*((c)->nic+((r)/4)) = (v))
- static Ctlr* dp83820ctlrhead;
- static Ctlr* dp83820ctlrtail;
- static Lock dp83820rblock; /* free receive Blocks */
- static Block* dp83820rbpool;
- static char* dp83820mibs[Nmibd] = {
- "RXErroredPkts",
- "RXFCSErrors",
- "RXMsdPktErrors",
- "RXFAErrors",
- "RXSymbolErrors",
- "RXFrameToLong",
- "RXIRLErrors",
- "RXBadOpcodes",
- "RXPauseFrames",
- "TXPauseFrames",
- "TXSQEErrors",
- };
- static int
- mdior(Ctlr* ctlr, int n)
- {
- int data, i, mear, r;
- mear = csr32r(ctlr, Mear);
- r = ~(Mdc|Mddir) & mear;
- data = 0;
- for(i = n-1; i >= 0; i--){
- if(csr32r(ctlr, Mear) & Mdio)
- data |= (1<<i);
- csr32w(ctlr, Mear, Mdc|r);
- csr32w(ctlr, Mear, r);
- }
- csr32w(ctlr, Mear, mear);
- return data;
- }
- static void
- mdiow(Ctlr* ctlr, int bits, int n)
- {
- int i, mear, r;
- mear = csr32r(ctlr, Mear);
- r = Mddir|(~Mdc & mear);
- for(i = n-1; i >= 0; i--){
- if(bits & (1<<i))
- r |= Mdio;
- else
- r &= ~Mdio;
- csr32w(ctlr, Mear, r);
- csr32w(ctlr, Mear, Mdc|r);
- }
- csr32w(ctlr, Mear, mear);
- }
- static int
- dp83820miimir(Mii* mii, int pa, int ra)
- {
- int data;
- Ctlr *ctlr;
- ctlr = mii->ctlr;
- /*
- * MII Management Interface Read.
- *
- * Preamble;
- * ST+OP+PA+RA;
- * LT + 16 data bits.
- */
- mdiow(ctlr, 0xFFFFFFFF, 32);
- mdiow(ctlr, 0x1800|(pa<<5)|ra, 14);
- data = mdior(ctlr, 18);
- if(data & 0x10000)
- return -1;
- return data & 0xFFFF;
- }
- static int
- dp83820miimiw(Mii* mii, int pa, int ra, int data)
- {
- Ctlr *ctlr;
- ctlr = mii->ctlr;
- /*
- * MII Management Interface Write.
- *
- * Preamble;
- * ST+OP+PA+RA+LT + 16 data bits;
- * Z.
- */
- mdiow(ctlr, 0xFFFFFFFF, 32);
- data &= 0xFFFF;
- data |= (0x05<<(5+5+2+16))|(pa<<(5+2+16))|(ra<<(2+16))|(0x02<<16);
- mdiow(ctlr, data, 32);
- return 0;
- }
- static Block *
- dp83820rballoc(Desc* desc)
- {
- Block *bp;
- if(desc->bp == nil){
- ilock(&dp83820rblock);
- if((bp = dp83820rbpool) == nil){
- iunlock(&dp83820rblock);
- desc->bp = nil;
- desc->cmdsts = Own;
- return nil;
- }
- dp83820rbpool = bp->next;
- bp->next = nil;
- iunlock(&dp83820rblock);
-
- desc->bufptr = PCIWADDR(bp->rp);
- desc->bp = bp;
- }
- else{
- bp = desc->bp;
- bp->rp = bp->lim - Rbsz;
- bp->wp = bp->rp;
- }
- coherence();
- desc->cmdsts = Intr|Rbsz;
- return bp;
- }
- static void
- dp83820rbfree(Block *bp)
- {
- bp->rp = bp->lim - Rbsz;
- bp->wp = bp->rp;
- ilock(&dp83820rblock);
- bp->next = dp83820rbpool;
- dp83820rbpool = bp;
- iunlock(&dp83820rblock);
- }
- static void
- dp83820halt(Ctlr* ctlr)
- {
- int i, timeo;
- ilock(&ctlr->ilock);
- csr32w(ctlr, Imr, 0);
- csr32w(ctlr, Ier, 0);
- csr32w(ctlr, Cr, Rxd|Txd);
- for(timeo = 0; timeo < 1000; timeo++){
- if(!(csr32r(ctlr, Cr) & (Rxe|Txe)))
- break;
- microdelay(1);
- }
- csr32w(ctlr, Mibc, Frz);
- iunlock(&ctlr->ilock);
- if(ctlr->rd != nil){
- for(i = 0; i < ctlr->nrd; i++){
- if(ctlr->rd[i].bp == nil)
- continue;
- freeb(ctlr->rd[i].bp);
- ctlr->rd[i].bp = nil;
- }
- }
- if(ctlr->td != nil){
- for(i = 0; i < ctlr->ntd; i++){
- if(ctlr->td[i].bp == nil)
- continue;
- freeb(ctlr->td[i].bp);
- ctlr->td[i].bp = nil;
- }
- }
- }
- static void
- dp83820cfg(Ctlr* ctlr)
- {
- int cfg;
- /*
- * Don't know how to deal with a TBI yet.
- */
- if(ctlr->mii == nil)
- return;
- /*
- * The polarity of these bits is at the mercy
- * of the board designer.
- * The correct answer for all speed and duplex questions
- * should be to query the phy.
- */
- cfg = csr32r(ctlr, Cfg);
- if(!(cfg & Dupsts)){
- ctlr->rxcfg |= Rxfd;
- ctlr->txcfg |= Csi|Hbi;
- iprint("83820: full duplex, ");
- }
- else{
- ctlr->rxcfg &= ~Rxfd;
- ctlr->txcfg &= ~(Csi|Hbi);
- iprint("83820: half duplex, ");
- }
- csr32w(ctlr, Rxcfg, ctlr->rxcfg);
- csr32w(ctlr, Txcfg, ctlr->txcfg);
- switch(cfg & (Spdsts1000|Spdsts100)){
- case Spdsts1000: /* 100Mbps */
- default: /* 10Mbps */
- ctlr->cfg &= ~Mode1000;
- if((cfg & (Spdsts1000|Spdsts100)) == Spdsts1000)
- iprint("100Mb/s\n");
- else
- iprint("10Mb/s\n");
- break;
- case Spdsts100: /* 1Gbps */
- ctlr->cfg |= Mode1000;
- iprint("1Gb/s\n");
- break;
- }
- csr32w(ctlr, Cfg, ctlr->cfg);
- }
- static void
- dp83820init(Ether* edev)
- {
- int i;
- Ctlr *ctlr;
- Desc *desc;
- uchar *alloc;
- ctlr = edev->ctlr;
- dp83820halt(ctlr);
- /*
- * Receiver
- */
- alloc = (uchar*)ROUNDUP((ulong)ctlr->alloc, 8);
- ctlr->rd = (Desc*)alloc;
- alloc += ctlr->nrd*sizeof(Desc);
- memset(ctlr->rd, 0, ctlr->nrd*sizeof(Desc));
- ctlr->rdx = 0;
- for(i = 0; i < ctlr->nrd; i++){
- desc = &ctlr->rd[i];
- desc->link = PCIWADDR(&ctlr->rd[NEXT(i, ctlr->nrd)]);
- if(dp83820rballoc(desc) == nil)
- continue;
- }
- csr32w(ctlr, Rxdphi, 0);
- csr32w(ctlr, Rxdp, PCIWADDR(ctlr->rd));
- for(i = 0; i < Eaddrlen; i += 2){
- csr32w(ctlr, Rfcr, i);
- csr32w(ctlr, Rfdr, (edev->ea[i+1]<<8)|edev->ea[i]);
- }
- csr32w(ctlr, Rfcr, Rfen|Aab|Apm);
- ctlr->rxcfg = Stripcrc|(((2*(ETHERMINTU+4))/8)<<RxdrthSHFT);
- ctlr->imr |= Rxorn|Rxidle|Rxearly|Rxdesc|Rxok;
- /*
- * Transmitter.
- */
- ctlr->td = (Desc*)alloc;
- memset(ctlr->td, 0, ctlr->ntd*sizeof(Desc));
- ctlr->tdh = ctlr->tdt = ctlr->ntq = 0;
- for(i = 0; i < ctlr->ntd; i++){
- desc = &ctlr->td[i];
- desc->link = PCIWADDR(&ctlr->td[NEXT(i, ctlr->ntd)]);
- }
- csr32w(ctlr, Txdphi, 0);
- csr32w(ctlr, Txdp, PCIWADDR(ctlr->td));
- ctlr->txcfg = Atp|(((2*(ETHERMINTU+4))/32)<<FlthSHFT)|((4096/32)<<TxdrthSHFT);
- ctlr->imr |= Txurn|Txidle|Txdesc|Txok;
- ilock(&ctlr->ilock);
- dp83820cfg(ctlr);
- csr32w(ctlr, Mibc, Aclr);
- ctlr->imr |= Mib;
- csr32w(ctlr, Imr, ctlr->imr);
- /* try coalescing adjacent interrupts; use hold-off interval of 100µs */
- csr32w(ctlr, Ihr, Ihctl|(1<<IhSHFT));
- csr32w(ctlr, Ier, Ien);
- csr32w(ctlr, Cr, Rxe|Txe);
- iunlock(&ctlr->ilock);
- }
- static void
- dp83820attach(Ether* edev)
- {
- Block *bp;
- Ctlr *ctlr;
- ctlr = edev->ctlr;
- qlock(&ctlr->alock);
- if(ctlr->alloc != nil){
- qunlock(&ctlr->alock);
- return;
- }
- if(waserror()){
- if(ctlr->mii != nil){
- free(ctlr->mii);
- ctlr->mii = nil;
- }
- if(ctlr->alloc != nil){
- free(ctlr->alloc);
- ctlr->alloc = nil;
- }
- qunlock(&ctlr->alock);
- nexterror();
- }
- if(!(ctlr->cfg & Tbien)){
- if((ctlr->mii = malloc(sizeof(Mii))) == nil)
- error(Enomem);
- ctlr->mii->ctlr = ctlr;
- ctlr->mii->mir = dp83820miimir;
- ctlr->mii->miw = dp83820miimiw;
- if(mii(ctlr->mii, ~0) == 0)
- error("no PHY");
- ctlr->cfg |= Dupstsien|Lnkstsien|Spdstsien;
- ctlr->imr |= Phy;
- }
- ctlr->nrd = Nrd;
- ctlr->nrb = Nrb;
- ctlr->ntd = Ntd;
- ctlr->alloc = mallocz((ctlr->nrd+ctlr->ntd)*sizeof(Desc) + 7, 0);
- if(ctlr->alloc == nil)
- error(Enomem);
- for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){
- if((bp = allocb(Rbsz)) == nil)
- break;
- bp->free = dp83820rbfree;
- dp83820rbfree(bp);
- }
- dp83820init(edev);
- qunlock(&ctlr->alock);
- poperror();
- }
- static void
- dp83820transmit(Ether* edev)
- {
- Block *bp;
- Ctlr *ctlr;
- Desc *desc;
- int cmdsts, r, x;
- ctlr = edev->ctlr;
- ilock(&ctlr->tlock);
- bp = nil;
- for(x = ctlr->tdh; ctlr->ntq; x = NEXT(x, ctlr->ntd)){
- desc = &ctlr->td[x];
- if((cmdsts = desc->cmdsts) & Own)
- break;
- if(!(cmdsts & Ok)){
- if(cmdsts & Ec)
- ctlr->ec++;
- if(cmdsts & Owc)
- ctlr->owc++;
- if(cmdsts & Ed)
- ctlr->ed++;
- if(cmdsts & Crs)
- ctlr->crs++;
- if(cmdsts & Tfu)
- ctlr->tfu++;
- if(cmdsts & Txa)
- ctlr->txa++;
- edev->oerrs++;
- }
- desc->bp->next = bp;
- bp = desc->bp;
- desc->bp = nil;
- ctlr->ntq--;
- }
- ctlr->tdh = x;
- if(bp != nil)
- freeblist(bp);
- x = ctlr->tdt;
- while(ctlr->ntq < (ctlr->ntd-1)){
- if((bp = qget(edev->oq)) == nil)
- break;
- desc = &ctlr->td[x];
- desc->bufptr = PCIWADDR(bp->rp);
- desc->bp = bp;
- ctlr->ntq++;
- coherence();
- desc->cmdsts = Own|Intr|BLEN(bp);
- x = NEXT(x, ctlr->ntd);
- }
- if(x != ctlr->tdt){
- ctlr->tdt = x;
- r = csr32r(ctlr, Cr);
- csr32w(ctlr, Cr, Txe|r);
- }
- iunlock(&ctlr->tlock);
- }
- static void
- dp83820interrupt(Ureg*, void* arg)
- {
- Block *bp;
- Ctlr *ctlr;
- Desc *desc;
- Ether *edev;
- int cmdsts, i, isr, r, x;
- edev = arg;
- ctlr = edev->ctlr;
- for(isr = csr32r(ctlr, Isr); isr & ctlr->imr; isr = csr32r(ctlr, Isr)){
- if(isr & (Rxorn|Rxidle|Rxearly|Rxerr|Rxdesc|Rxok)){
- x = ctlr->rdx;
- desc = &ctlr->rd[x];
- while((cmdsts = desc->cmdsts) & Own){
- if((cmdsts & Ok) && desc->bp != nil){
- bp = desc->bp;
- desc->bp = nil;
- bp->wp += cmdsts & SizeMASK;
- etheriq(edev, bp, 1);
- }
- //else if(!(cmdsts & Ok)){
- // iprint("dp83820: rx %8.8uX:", cmdsts);
- // bp = desc->bp;
- // for(i = 0; i < 20; i++)
- // iprint(" %2.2uX", bp->rp[i]);
- // iprint("\n");
- //}
- dp83820rballoc(desc);
- x = NEXT(x, ctlr->nrd);
- desc = &ctlr->rd[x];
- }
- ctlr->rdx = x;
- if(isr & Rxidle){
- r = csr32r(ctlr, Cr);
- csr32w(ctlr, Cr, Rxe|r);
- ctlr->rxidle++;
- }
- isr &= ~(Rxorn|Rxidle|Rxearly|Rxerr|Rxdesc|Rxok);
- }
- if(isr & Txurn){
- x = (ctlr->txcfg & TxdrthMASK)>>TxdrthSHFT;
- r = (ctlr->txcfg & FlthMASK)>>FlthSHFT;
- if(x < ((TxdrthMASK)>>TxdrthSHFT)
- && x < (2048/32 - r)){
- ctlr->txcfg &= ~TxdrthMASK;
- x++;
- ctlr->txcfg |= x<<TxdrthSHFT;
- csr32w(ctlr, Txcfg, ctlr->txcfg);
- }
- }
- if(isr & (Txurn|Txidle|Txdesc|Txok)){
- dp83820transmit(edev);
- isr &= ~(Txurn|Txidle|Txdesc|Txok);
- }
- if(isr & Mib){
- for(i = 0; i < Nmibd; i++){
- r = csr32r(ctlr, Mibd+(i*sizeof(int)));
- ctlr->mibd[i] += r & 0xFFFF;
- }
- isr &= ~Mib;
- }
- if((isr & Phy) && ctlr->mii != nil){
- ctlr->mii->mir(ctlr->mii, 1, Bmsr);
- print("phy: cfg %8.8uX bmsr %4.4uX\n",
- csr32r(ctlr, Cfg),
- ctlr->mii->mir(ctlr->mii, 1, Bmsr));
- dp83820cfg(ctlr);
- isr &= ~Phy;
- }
- if(isr)
- iprint("dp83820: isr %8.8uX\n", isr);
- }
- }
- static long
- dp83820ifstat(Ether* edev, void* a, long n, ulong offset)
- {
- char *p;
- Ctlr *ctlr;
- int i, l, r;
- ctlr = edev->ctlr;
- edev->crcs = ctlr->mibd[Mibd+(1*sizeof(int))];
- edev->frames = ctlr->mibd[Mibd+(3*sizeof(int))];
- edev->buffs = ctlr->mibd[Mibd+(5*sizeof(int))];
- edev->overflows = ctlr->mibd[Mibd+(2*sizeof(int))];
- if(n == 0)
- return 0;
- p = malloc(READSTR);
- l = 0;
- for(i = 0; i < Nmibd; i++){
- r = csr32r(ctlr, Mibd+(i*sizeof(int)));
- ctlr->mibd[i] += r & 0xFFFF;
- if(ctlr->mibd[i] != 0 && dp83820mibs[i] != nil)
- l += snprint(p+l, READSTR-l, "%s: %ud %ud\n",
- dp83820mibs[i], ctlr->mibd[i], r);
- }
- l += snprint(p+l, READSTR-l, "rxidle %d\n", ctlr->rxidle);
- l += snprint(p+l, READSTR-l, "ec %d\n", ctlr->ec);
- l += snprint(p+l, READSTR-l, "owc %d\n", ctlr->owc);
- l += snprint(p+l, READSTR-l, "ed %d\n", ctlr->ed);
- l += snprint(p+l, READSTR-l, "crs %d\n", ctlr->crs);
- l += snprint(p+l, READSTR-l, "tfu %d\n", ctlr->tfu);
- l += snprint(p+l, READSTR-l, "txa %d\n", ctlr->txa);
- l += snprint(p+l, READSTR, "rom:");
- for(i = 0; i < 0x10; i++){
- if(i && ((i & 0x07) == 0))
- l += snprint(p+l, READSTR-l, "\n ");
- l += snprint(p+l, READSTR-l, " %4.4uX", ctlr->eeprom[i]);
- }
- l += snprint(p+l, READSTR-l, "\n");
- if(ctlr->mii != nil && ctlr->mii->curphy != nil){
- l += snprint(p+l, READSTR, "phy:");
- for(i = 0; i < NMiiPhyr; i++){
- if(i && ((i & 0x07) == 0))
- l += snprint(p+l, READSTR-l, "\n ");
- r = miimir(ctlr->mii, i);
- l += snprint(p+l, READSTR-l, " %4.4uX", r);
- }
- snprint(p+l, READSTR-l, "\n");
- }
- n = readstr(offset, a, n, p);
- free(p);
- return n;
- }
- static void
- dp83820promiscuous(void* arg, int on)
- {
- USED(arg, on);
- }
- static int
- atc93c46r(Ctlr* ctlr, int address)
- {
- int data, i, mear, r, size;
- /*
- * Analog Technology, Inc. ATC93C46
- * or equivalent serial EEPROM.
- */
- mear = csr32r(ctlr, Mear);
- mear &= ~(Eesel|Eeclk|Eedo|Eedi);
- r = Eesel|mear;
- reread:
- csr32w(ctlr, Mear, r);
- data = 0x06;
- for(i = 3-1; i >= 0; i--){
- if(data & (1<<i))
- r |= Eedi;
- else
- r &= ~Eedi;
- csr32w(ctlr, Mear, r);
- csr32w(ctlr, Mear, Eeclk|r);
- microdelay(1);
- csr32w(ctlr, Mear, r);
- microdelay(1);
- }
- /*
- * First time through must work out the EEPROM size.
- */
- if((size = ctlr->eepromsz) == 0)
- size = 8;
- for(size = size-1; size >= 0; size--){
- if(address & (1<<size))
- r |= Eedi;
- else
- r &= ~Eedi;
- csr32w(ctlr, Mear, r);
- microdelay(1);
- csr32w(ctlr, Mear, Eeclk|r);
- microdelay(1);
- csr32w(ctlr, Mear, r);
- microdelay(1);
- if(!(csr32r(ctlr, Mear) & Eedo))
- break;
- }
- r &= ~Eedi;
- data = 0;
- for(i = 16-1; i >= 0; i--){
- csr32w(ctlr, Mear, Eeclk|r);
- microdelay(1);
- if(csr32r(ctlr, Mear) & Eedo)
- data |= (1<<i);
- csr32w(ctlr, Mear, r);
- microdelay(1);
- }
- csr32w(ctlr, Mear, mear);
- if(ctlr->eepromsz == 0){
- ctlr->eepromsz = 8-size;
- ctlr->eeprom = malloc((1<<ctlr->eepromsz)*sizeof(ushort));
- goto reread;
- }
- return data;
- }
- static int
- dp83820reset(Ctlr* ctlr)
- {
- int i, r;
- unsigned char sum;
- /*
- * Soft reset the controller;
- * read the EEPROM to get the initial settings
- * of the Cfg and Gpior bits which should be cleared by
- * the reset.
- */
- csr32w(ctlr, Cr, Rst);
- delay(1);
- while(csr32r(ctlr, Cr) & Rst)
- delay(1);
- atc93c46r(ctlr, 0);
- if(ctlr->eeprom == nil)
- return -1;
- sum = 0;
- for(i = 0; i < 0x0E; i++){
- r = atc93c46r(ctlr, i);
- ctlr->eeprom[i] = r;
- sum += r;
- sum += r>>8;
- }
- if(sum != 0){
- print("dp83820reset: bad EEPROM checksum\n");
- return -1;
- }
- #ifdef notdef
- csr32w(ctlr, Gpior, ctlr->eeprom[4]);
- cfg = Extstsen|Exd;
- r = csr32r(ctlr, Cfg);
- if(ctlr->eeprom[5] & 0x0001)
- cfg |= Ext125;
- if(ctlr->eeprom[5] & 0x0002)
- cfg |= M64addren;
- if((ctlr->eeprom[5] & 0x0004) && (r & Pci64det))
- cfg |= Data64en;
- if(ctlr->eeprom[5] & 0x0008)
- cfg |= T64addren;
- if(!(pcicfgr16(ctlr->pcidev, PciPCR) & 0x10))
- cfg |= Mwidis;
- if(ctlr->eeprom[5] & 0x0020)
- cfg |= Mrmdis;
- if(ctlr->eeprom[5] & 0x0080)
- cfg |= Mode1000;
- if(ctlr->eeprom[5] & 0x0200)
- cfg |= Tbien|Mode1000;
- /*
- * What about RO bits we might have destroyed with Rst?
- * What about Exd, Tmrtest, Extstsen, Pintctl?
- * Why does it think it has detected a 64-bit bus when
- * it hasn't?
- */
- #else
- //r = csr32r(ctlr, Cfg);
- //r &= ~(Mode1000|T64addren|Data64en|M64addren);
- //csr32w(ctlr, Cfg, r);
- //csr32w(ctlr, Cfg, 0x2000);
- #endif /* notdef */
- ctlr->cfg = csr32r(ctlr, Cfg);
- print("cfg %8.8uX pcicfg %8.8uX\n", ctlr->cfg, pcicfgr32(ctlr->pcidev, PciPCR));
- ctlr->cfg &= ~(T64addren|Data64en|M64addren);
- csr32w(ctlr, Cfg, ctlr->cfg);
- csr32w(ctlr, Mibc, Aclr|Frz);
- return 0;
- }
- static void
- dp83820pci(void)
- {
- void *mem;
- Pcidev *p;
- Ctlr *ctlr;
- p = nil;
- while(p = pcimatch(p, 0, 0)){
- if(p->ccrb != 0x02 || p->ccru != 0)
- continue;
- switch((p->did<<16)|p->vid){
- default:
- continue;
- case (0x0022<<16)|0x100B: /* DP83820 (Gig-NIC) */
- break;
- }
- mem = vmap(p->mem[1].bar & ~0x0F, p->mem[1].size);
- if(mem == 0){
- print("DP83820: can't map %8.8luX\n", p->mem[1].bar);
- continue;
- }
- ctlr = malloc(sizeof(Ctlr));
- ctlr->port = p->mem[1].bar & ~0x0F;
- ctlr->pcidev = p;
- ctlr->id = (p->did<<16)|p->vid;
- ctlr->nic = mem;
- if(dp83820reset(ctlr)){
- free(ctlr);
- continue;
- }
- pcisetbme(p);
- if(dp83820ctlrhead != nil)
- dp83820ctlrtail->next = ctlr;
- else
- dp83820ctlrhead = ctlr;
- dp83820ctlrtail = ctlr;
- }
- }
- static int
- dp83820pnp(Ether* edev)
- {
- int i;
- Ctlr *ctlr;
- uchar ea[Eaddrlen];
- if(dp83820ctlrhead == nil)
- dp83820pci();
- /*
- * Any adapter matches if no edev->port is supplied,
- * otherwise the ports must match.
- */
- for(ctlr = dp83820ctlrhead; ctlr != nil; ctlr = ctlr->next){
- if(ctlr->active)
- continue;
- if(edev->port == 0 || edev->port == ctlr->port){
- ctlr->active = 1;
- break;
- }
- }
- if(ctlr == nil)
- return -1;
- edev->ctlr = ctlr;
- edev->port = ctlr->port;
- edev->irq = ctlr->pcidev->intl;
- edev->tbdf = ctlr->pcidev->tbdf;
- edev->mbps = 1000;
- /*
- * Check if the adapter's station address is to be overridden.
- * If not, read it from the EEPROM and set in ether->ea prior to
- * loading the station address in the hardware.
- */
- memset(ea, 0, Eaddrlen);
- if(memcmp(ea, edev->ea, Eaddrlen) == 0){
- for(i = 0; i < Eaddrlen/2; i++){
- edev->ea[2*i] = ctlr->eeprom[0x0C-i];
- edev->ea[2*i+1] = ctlr->eeprom[0x0C-i]>>8;
- }
- }
- edev->attach = dp83820attach;
- edev->transmit = dp83820transmit;
- edev->interrupt = dp83820interrupt;
- edev->ifstat = dp83820ifstat;
- edev->arg = edev;
- edev->promiscuous = dp83820promiscuous;
- return 0;
- }
- void
- etherdp83820link(void)
- {
- addethercard("DP83820", dp83820pnp);
- }
|