123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269 |
- /*
- * National Semiconductor DP83820 & DP83821
- * 10/100/1000 Mb/s Ethernet Network Interface Controller
- * (Gig-NIC).
- * Driver assumes little-endian and 32-bit host throughout.
- */
- #ifdef FS
- #include "all.h"
- #include "io.h"
- #include "mem.h"
- #include "../ip/ip.h"
- #else
- #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 "ethermii.h"
- #include "compat.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, Udppkt are struct types in the fs kernel */
- Ippacket = 0x00020000, /* IP Packet */
- Iperr = 0x00040000, /* IP Checksum Error */
- Tcppkt = 0x00080000, /* TCP Packet */
- Tcperr = 0x00100000, /* TCP Checksum Error */
- Udppacket = 0x00200000, /* UDP Packet */
- Udperr = 0x00400000, /* UDP Checksum Error */
- };
- /*
- * adjust these, keeping in mind that at 1Gb/s, a 1514-byte packet is
- * sent or received in 12µs. Ignoring mandatory inter-packet gaps,
- * a ring of 32 buffers will take 388µs to fill or empty; 64 buffers
- * will take 775µs; 256 will take 3.1ms.
- */
- enum {
- Nrd = 64, // was 64 then 450
- Nrb = 4*Nrd,
- Rbsz = ROUNDUP(sizeof(Etherpkt)+8, 8),
- Ntd = Nrd, // was 32 then 450
- };
- 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 data & 0xFFFF; /* TODO: what's the caller expect here? */
- }
- /*
- * return free Block+buffer ready for input of up to MTU bytes.
- * desc->bp is also set to the return value.
- */
- 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;
- iprint("dp83820rballoc: out of buffers\n");
- return nil;
- }
- dp83820rbpool = bp->next;
- bp->next = nil;
- iunlock(&dp83820rblock);
- desc->bufptr = PCIWADDR(bp->rp);
- desc->bp = bp;
- }
- else{
- bp = desc->bp;
- BLKRESET(bp);
- }
- coherence();
- desc->cmdsts = Intr|Rbsz;
- return bp;
- }
- /* should be called via freeb() */
- static void
- dp83820rbfree(Block *bp)
- {
- BLKRESET(bp);
- ilock(&dp83820rblock);
- bp->next = dp83820rbpool;
- dp83820rbpool = bp;
- iunlock(&dp83820rblock);
- }
- static void
- dp83820halt(Ctlr* ctlr)
- {
- int i;
- ilock(&ctlr->ilock);
- csr32w(ctlr, Imr, 0);
- csr32w(ctlr, Ier, 0);
- csr32w(ctlr, Cr, Rxd|Txd);
- /* TODO: limit this; don't wait forever with a lock held */
- while(csr32r(ctlr, Cr) & (Rxe|Txe))
- ;
- 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) {
- iprint("83820: got tbi, not phy\n");
- 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) {
- print("dp83820init: out of buffers\n");
- 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()){
- err:
- if(ctlr->mii != nil){
- free(ctlr->mii);
- ctlr->mii = nil;
- }
- if(ctlr->alloc != nil){
- free(ctlr->alloc);
- ctlr->alloc = nil;
- }
- 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;
- }
- /* allocate all Descs */
- 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);
- /*
- * allocate receive Blocks+buffers, add all to receive Block+buffer pool
- */
- for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){
- bp = iallocb(Rbsz);
- #ifdef FS
- bp->flags |= Mbrcvbuf;
- #endif
- bp->free = dp83820rbfree; /* to be called via freeb() */
- dp83820rbfree(bp);
- }
- /* attaches a receive Block+buffer to each receive Desc */
- 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++;
- #ifndef FS
- edev->oerrs++;
- #endif
- }
- desc->bp->next = bp; /* chain transmitted Blocks together */
- bp = desc->bp;
- desc->bp = nil; /* unlink them from Descs */
- ctlr->ntq--;
- }
- /* free Blocks+buffers comprising the packets just sent */
- ctlr->tdh = x;
- if(bp != nil)
- freeblist(bp);
- x = ctlr->tdt;
- while(ctlr->ntq < (ctlr->ntd-1)){
- bp = etheroq(edev); /* get head of transmit q */
- if(bp == nil)
- break;
- desc = &ctlr->td[x];
- desc->bufptr = PCIWADDR(bp->rp);
- desc->bp = bp; /* attach to Desc */
- ctlr->ntq++;
- coherence();
- desc->cmdsts = Own|Intr|BLEN(bp); /* fire! */
- x = NEXT(x, ctlr->ntd);
- }
- if (ctlr->ntq >= ctlr->ntd-1)
- iprint("83820: xmit q full, Ntd=%d\n", 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 i, isr, r, x, rcvd = 0;
- edev = arg;
- ctlr = edev->ctlr;
- for(isr = csr32r(ctlr, Isr); isr & ctlr->imr; isr = csr32r(ctlr, Isr)){
- if(isr & (Rxorn|Rxidle|Rxearly|Rxdesc|Rxok)){
- x = ctlr->rdx;
- desc = &ctlr->rd[x];
- while(desc->cmdsts & Own){
- if((desc->cmdsts & Ok) && desc->bp != nil){
- /* unlink rcv. Block from Desc */
- bp = desc->bp;
- desc->bp = nil;
- /* store its length, add to input q */
- INCRPTR(bp, desc->cmdsts & SizeMASK);
- ETHERIQ(edev, bp, 1);
- rcvd++;
- }
- /* replace rcv. Block just detached from Desc */
- if (dp83820rballoc(desc) == nil)
- iprint(
- "dp83820interrupt: rballoc failed\n");
- x = NEXT(x, ctlr->nrd);
- desc = &ctlr->rd[x];
- }
- ctlr->rdx = x;
- if (rcvd >= ctlr->nrd-1)
- iprint("83820: rcv q full, Nrd=%d\n", Nrd);
- if(isr & Rxidle){
- /* resume reading packets */
- r = csr32r(ctlr, Cr);
- csr32w(ctlr, Cr, Rxe|r);
- ctlr->rxidle++;
- }
- isr &= ~(Rxorn|Rxidle|Rxearly|Rxdesc|Rxok);
- }
- if(isr & (Txurn|Txidle|Txdesc|Txok)){
- /* toss completed packets, q new ones, fire */
- 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);
- }
- }
- #ifndef FS
- static long
- dp83820ifstat(Ether* edev, void* a, long n, ulong offset)
- {
- char *p;
- Ctlr *ctlr;
- int i, l, r;
- MiiPhy *phy;
- ctlr = edev->ctlr;
- edev->crcs = ctlr->mibd[1];
- edev->frames = ctlr->mibd[3];
- edev->buffs = ctlr->mibd[5];
- edev->overflows = ctlr->mibd[2];
- 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(0 && ctlr->mii != nil && (phy = 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 ");
- /* phy->r no longer exists */
- // l += snprint(p+l, READSTR-l, " %4.4uX", phy->r[i]);
- }
- snprint(p+l, READSTR-l, "\n");
- }
- n = readstr(offset, a, n, p);
- free(p);
- return n;
- }
- #endif /* FS */
- 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);
- 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;
- }
- 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);
- /* TODO: limit this; don't wait forever */
- while(csr32r(ctlr, Cr) & Rst)
- delay(1);
- atc93c46r(ctlr, 0);
- 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;
- }
- // from pci.c
- enum {
- Pcinetctlr = 0x02, /* network controller */
- // PciCCRp = 0x09, /* programming interface class code */
- // PciCCRu = 0x0A, /* sub-class code */
- // PciCCRb = 0x0B, /* base class code */
- };
- static void
- dp83820pci(void)
- {
- int port;
- Pcidev *p;
- Ctlr *ctlr;
- p = nil;
- while(p = pcimatch(p, 0, 0)){
- /* ccru is a short in the FS kernel, thus the cast to uchar */
- if(p->ccrb != Pcinetctlr || (uchar)p->ccru != 0)
- continue;
- switch((p->did<<16)|p->vid){
- default:
- continue;
- case (0x0022<<16)|0x100B: /* DP83820 (Gig-NIC) */
- break;
- }
- port = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0);
- if(port == 0){
- print("DP83820: can't map %8.8lux\n", p->mem[1].bar);
- continue;
- }
- /* malloc only zeroes storage if Npadlong!=0, so use mallocz */
- ctlr = mallocz(sizeof(Ctlr), 1);
- ctlr->port = port;
- ctlr->pcidev = p;
- ctlr->id = (p->did<<16)|p->vid;
- #ifdef notdef
- /*
- * bar[0] is the I/O port register address and
- * bar[1] is the memory-mapped register address.
- */
- if (ioalloc(p->mem[0].bar & ~0x0F, p->mem[0].size, 0, "dp83820")
- < 0) {
- print("dp83820: port 0x%uX in use\n", ctlr->port);
- free(ctlr);
- continue;
- }
- #endif
- ctlr->nic = KADDR(ctlr->port);
- if(dp83820reset(ctlr)){
- free(ctlr);
- continue;
- }
- pcisetbme(p);
- if(dp83820ctlrhead != nil)
- dp83820ctlrtail->next = ctlr;
- else
- dp83820ctlrhead = ctlr;
- dp83820ctlrtail = ctlr;
- }
- }
- 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;
- #ifndef FS
- edev->ifstat = dp83820ifstat;
- edev->arg = edev;
- edev->promiscuous = dp83820promiscuous;
- #endif
- return 0;
- }
- #ifndef FS
- void
- etherdp83820link(void)
- {
- addethercard("DP83820", dp83820pnp);
- }
- #endif
|