support all controllers in the intel _PCIe* Family of Gigabit Ethernet Controllers Softwarer Developer's Manual_ rev 2.6 ref no. 21489. measured AoE performance: up to 240MB/s on two 82573 ports using 8k jumbograms. 1. support intel 82566 mm/dm/v, 82571, 82572, 82573[ev]. tested with intel pro 1000/pt single (82572) and 1000/pt dual and quad (82571) and onboard 82563[ev] cards. 82566 untested. 2. track link status and link speed correctly keep stats on link speed changes to aid debugging. 3. performance; use descriptor writeback (Td bit) instead of syncronous mmio for tx ring sweep, correct some wrongly-set bits. 4. performance; use qlock not ilock around transmit. 5. calculate the mac as per yellow book specificaiton. 6. jumbo frame support. Reference: /n/sources/patch/applied/82563-update2 Date: Sat Sep 1 16:59:58 CES 2007 Signed-off-by: quanstro@quanstro.net --- /sys/src/9/pc/ether82563.c Sat Sep 1 16:50:57 2007 +++ /sys/src/9/pc/ether82563.c Sat Sep 1 16:50:54 2007 @@ -1,5 +1,5 @@ /* - * Intel 82563 Gigabit Ethernet Controller + * Intel 82563, 82566, 82571, 82572, 82573[ev] Gigabit Ethernet Controller */ #include "u.h" #include "../port/lib.h" @@ -17,7 +17,7 @@ * these are in the order they appear in the manual, not numeric order. * It was too hard to find them in the book. Ref 21489, rev 2.6 */ - + enum { /* General */ @@ -39,10 +39,12 @@ Rxcw = 0x00000180, /* Receive Configuration Word */ Ledctl = 0x00000E00, /* LED control */ Pba = 0x00001000, /* Packet Buffer Allocation */ + Pbs = 0x00001008, /* Packet Buffer Size */ /* Interrupt */ Icr = 0x000000C0, /* Interrupt Cause Read */ + Itr = 0x000000c4, /* Interrupt Throttling Rate */ Ics = 0x000000C8, /* Interrupt Cause Set */ Ims = 0x000000D0, /* Interrupt Mask Set/Read */ Imc = 0x000000D8, /* Interrupt mask Clear */ @@ -75,8 +77,8 @@ Rxcsum = 0x00005000, /* Checksum Control */ Rfctl = 0x00005008, /* Filter Control */ Mta = 0x00005200, /* Multicast Table Array */ - Ral = 0x00005400, /* Address Low */ - Rah = 0x00005404, /* Address High */ + Ral = 0x00005400, /* Receive Address Low */ + Rah = 0x00005404, /* Receive Address High */ Vfta = 0x00005600, /* VLAN Filter Table Array */ Mrqc = 0x00005818, /* Multiple Receive Queues Command */ Rssim = 0x00005864, /* RSS Interrupt Mask */ @@ -86,8 +88,9 @@ /* Transmit */ - Tctl = 0x00000400, /* Control */ - Tipg = 0x00000410, /* IPG */ + Tctl = 0x00000400, /* Transmit Control */ + Tipg = 0x00000410, /* Transmit IPG */ + Tkabgtxd = 0x00003004, /* glci afe band gap transmit ref data, or something */ Tdbal = 0x00003800, /* Tdesc Base Address Low */ Tdbah = 0x00003804, /* Tdesc Base Address High */ Tdlen = 0x00003808, /* Descriptor Length */ @@ -112,43 +115,42 @@ Gotcl = 0x90/4, /* Good Octets Transmitted Count */ Torl = 0xC0/4, /* Total Octets Received */ Totl = 0xC8/4, /* Total Octets Transmitted */ - Nstatistics = 64, - + Nstatistics = 0x124/4, }; enum { /* Ctrl */ - GIOmd = (1<<2), /* BIO master disable */ - Lrst = (1<<3), /* link reset */ - Slu = (1<<6), /* Set Link Up */ - SspeedMASK = (3<<8), /* Speed Selection */ + GIOmd = 1<<2, /* BIO master disable */ + Lrst = 1<<3, /* link reset */ + Slu = 1<<6, /* Set Link Up */ + SspeedMASK = 3<<8, /* Speed Selection */ SspeedSHIFT = 8, Sspeed10 = 0x00000000, /* 10Mb/s */ Sspeed100 = 0x00000100, /* 100Mb/s */ Sspeed1000 = 0x00000200, /* 1000Mb/s */ - Frcspd = (1<<11), /* Force Speed */ - Frcdplx = (1<<12), /* Force Duplex */ + Frcspd = 1<<11, /* Force Speed */ + Frcdplx = 1<<12, /* Force Duplex */ SwdpinsloMASK = 0x003C0000, /* Software Defined Pins - lo nibble */ SwdpinsloSHIFT = 18, SwdpioloMASK = 0x03C00000, /* Software Defined Pins - I or O */ SwdpioloSHIFT = 22, - Devrst = (1<<26), /* Device Reset */ - Rfce = (1<<27), /* Receive Flow Control Enable */ - Tfce = (1<<28), /* Transmit Flow Control Enable */ - Vme = (1<<30), /* VLAN Mode Enable */ - Phy_rst = (1<<31), /* Phy Reset */ + Devrst = 1<<26, /* Device Reset */ + Rfce = 1<<27, /* Receive Flow Control Enable */ + Tfce = 1<<28, /* Transmit Flow Control Enable */ + Vme = 1<<30, /* VLAN Mode Enable */ + Phyrst = 1<<31, /* Phy Reset */ }; enum { /* Status */ - Lu = (1<<1), /* Link Up */ - Lanid = (3<<2), /* mask for Lan ID. - Txoff = (1<<4), /* Transmission Paused */ - Tbimode = (1<<5), /* TBI Mode Indication */ + Lu = 1<<1, /* Link Up */ + Lanid = 3<<2, /* mask for Lan ID. + Txoff = 1<<4, /* Transmission Paused */ + Tbimode = 1<<5, /* TBI Mode Indication */ SpeedMASK = 0x000000C0, Speed10 = 0x00000000, /* 10Mb/s */ Speed100 = 0x00000040, /* 100Mb/s */ Speed1000 = 0x00000080, /* 1000Mb/s */ - Phyra = (1<<10), /* PHY Reset Asserted */ - GIOme = (1<<19), /* GIO Master Enable Status */ + Phyra = 1<<10, /* PHY Reset Asserted */ + GIOme = 1<<19, /* GIO Master Enable Status */ }; enum { /* Ctrl and Status */ @@ -160,25 +162,25 @@ }; enum { /* Eec */ - Sk = (1<<0), /* Clock input to the EEPROM */ - Cs = (1<<1), /* Chip Select */ - Di = (1<<2), /* Data Input to the EEPROM */ - Do = (1<<3), /* Data Output from the EEPROM */ - Areq = (1<<6), /* EEPROM Access Request */ - Agnt = (1<<7), /* EEPROM Access Grant */ + Sk = 1<<0, /* Clock input to the EEPROM */ + Cs = 1<<1, /* Chip Select */ + Di = 1<<2, /* Data Input to the EEPROM */ + Do = 1<<3, /* Data Output from the EEPROM */ + Areq = 1<<6, /* EEPROM Access Request */ + Agnt = 1<<7, /* EEPROM Access Grant */ }; enum { /* Eerd */ - ee_start = (1<<0), /* Start Read */ - ee_done = (1<<1), /* Read done */ - ee_addr = (0xfff8<<2), /* Read address [15:2] */ - ee_data = (0xffff<<16), /* Read Data; Data returned from eeprom/nvm */ + ee_start = 1<<0, /* Start Read */ + ee_done = 1<<1, /* Read done */ + ee_addr = 0xfff8<<2, /* Read address [15:2] */ + ee_data = 0xffff<<16, /* Read Data; Data returned from eeprom/nvm */ }; enum { /* Ctrlext */ - Asdchk = (1<<12), /* ASD Check */ - Eerst = (1<<13), /* EEPROM Reset */ - Spdbyps = (1<<15), /* Speed Select Bypass */ + Asdchk = 1<<12, /* ASD Check */ + Eerst = 1<<13, /* EEPROM Reset */ + Spdbyps = 1<<15, /* Speed Select Bypass */ }; enum { /* EEPROM content offsets */ @@ -206,6 +208,14 @@ MDIe = 0x40000000, /* Error */ }; +enum{ /* Mdic secondary status register */ + Physsr = 17, /* phy secondary status register */ + Phyier = 18, /* phy interrupt enable register */ + Phypage = 22, /* phy page register */ + Rtlink = 1<<10, /* realtime link status */ + Phyan = 1<<11, /* phy has autonegotiated */ +}; + enum { /* Icr, Ics, Ims, Imc */ Txdw = 0x00000001, /* Transmit Descriptor Written Back */ Txqe = 0x00000002, /* Transmit Queue Empty */ @@ -220,6 +230,7 @@ Gpi1 = 0x00001000, Gpi2 = 0x00002000, Gpi3 = 0x00004000, + Ack = 0x00020000, /* Receive ACK frame */ }; enum { /* Txcw */ @@ -227,8 +238,8 @@ TxcwHd = 0x00000040, /* Half Duplex */ TxcwPauseMASK = 0x00000180, /* Pause */ TxcwPauseSHIFT = 7, - TxcwPs = (1<type] + typedef struct Ctlr Ctlr; struct Ctlr { int port; - Pcidev* pcidev; - Ctlr* next; + Pcidev *pcidev; + Ctlr *next; int active; int started; - int id; + int type; int cls; ushort eeprom[0x40]; QLock alock; /* attach */ - void* alloc; /* receive/transmit descriptors */ + void *alloc; /* receive/transmit descriptors */ int nrd; int ntd; int nrb; /* how many this Ctlr has in the pool */ + int rbsz; - int* nic; + int *nic; Lock imlock; int im; /* interrupt mask */ Rendez lrendez; int lim; - int link; - QLock slock; uint statistics[Nstatistics]; uint lsleep; @@ -412,6 +448,7 @@ uint ixsm; uint ipcs; uint tcpcs; + uint speeds[4]; uchar ra[Eaddrlen]; /* receive address */ ulong mta[128]; /* multicast table array */ @@ -419,29 +456,27 @@ Rendez rrendez; int rim; int rdfree; - Rd* rdba; /* receive descriptor base address */ - Block** rb; /* receive buffers */ + Rd *rdba; /* receive descriptor base address */ + Block **rb; /* receive buffers */ int rdh; /* receive descriptor head */ int rdt; /* receive descriptor tail */ int rdtr; /* receive delay timer ring value */ - int radv; /* receive interrupt absolute delay timer */ + int radv; /* recieve interrupt absolute delay timer */ - Lock tlock; + Rendez trendez; + QLock tlock; int tbusy; int tdfree; - Td* tdba; /* transmit descriptor base address */ - Block** tb; /* transmit buffers */ + Td *tdba; /* transmit descriptor base address */ + Block **tb; /* transmit buffers */ int tdh; /* transmit descriptor head */ int tdt; /* transmit descriptor tail */ int txcw; int fcrtl; int fcrth; -}; -enum{ - Easize = 6, - Maxmac = 16, + uint pba; /* packet buffer allocation */ }; #define csr32r(c, r) (*((c)->nic+((r)/4))) @@ -453,7 +488,7 @@ static Lock i82563rblock; /* free receive Blocks */ static Block* i82563rbpool; -static char* statistics[Nstatistics] = { +static char* statistics[] = { "CRC Error", "Alignment Error", "Symbol Error", @@ -482,7 +517,7 @@ "Packets Received (128-255 Bytes)", "Packets Received (256-511 Bytes)", "Packets Received (512-1023 Bytes)", - "Packets Received (1024-1522 Bytes)", + "Packets Received (1024-mtu Bytes)", "Good Packets Received", "Broadcast Packets Received", "Multicast Packets Received", @@ -499,9 +534,9 @@ "Receive Fragment", "Receive Oversize", "Receive Jabber", - nil, - nil, - nil, + "Management Packets Rx", + "Management Packets Drop", + "Management Packets Tx", "Total Octets Received", nil, "Total Octets Transmitted", @@ -513,28 +548,38 @@ "Packets Transmitted (128-255 Bytes)", "Packets Transmitted (256-511 Bytes)", "Packets Transmitted (512-1023 Bytes)", - "Packets Transmitted (1024-1522 Bytes)", + "Packets Transmitted (1024-mtu Bytes)", "Multicast Packets Transmitted", "Broadcast Packets Transmitted", "TCP Segmentation Context Transmitted", "TCP Segmentation Context Fail", + "Interrupt Assertion", + "Interrupt Rx Pkt Timer", + "Interrupt Rx Abs Timer", + "Interrupt Tx Pkt Timer", + "Interrupt Tx Abs Timer", + "Interrupt Tx Queue Empty", + "Interrupt Tx Desc Low", + "Interrupt Rx Min", + "Interrupt Rx Overrun", }; static long i82563ifstat(Ether* edev, void* a, long n, ulong offset) { Ctlr *ctlr; - char *p, *s; - int i, l, r; + char *s, *p, *e, *stat; + int i, r; uvlong tuvl, ruvl; ctlr = edev->ctlr; qlock(&ctlr->slock); - p = malloc(2*READSTR); - l = 0; + p = s = malloc(2*READSTR); + e = p+2*READSTR; + for(i = 0; i < Nstatistics; i++){ r = csr32r(ctlr, Statistics+i*4); - if((s = statistics[i]) == nil) + if((stat = statistics[i]) == nil) continue; switch(i){ case Gorcl: @@ -550,8 +595,7 @@ continue; ctlr->statistics[i] = tuvl; ctlr->statistics[i+1] = tuvl>>32; - l += snprint(p+l, 2*READSTR-l, "%s: %llud %llud\n", - s, tuvl, ruvl); + p = seprint(p, e, "%s: %llud %llud\n", stat, tuvl, ruvl); i++; break; @@ -559,33 +603,39 @@ ctlr->statistics[i] += r; if(ctlr->statistics[i] == 0) continue; - l += snprint(p+l, 2*READSTR-l, "%s: %ud %ud\n", - s, ctlr->statistics[i], r); + p = seprint(p, e, "%s: %ud %ud\n", stat, ctlr->statistics[i], r); break; } } - l += snprint(p+l, 2*READSTR-l, "lintr: %ud %ud\n", - ctlr->lintr, ctlr->lsleep); - l += snprint(p+l, 2*READSTR-l, "rintr: %ud %ud\n", - ctlr->rintr, ctlr->rsleep); - l += snprint(p+l, 2*READSTR-l, "tintr: %ud %ud\n", - ctlr->tintr, ctlr->txdw); - l += snprint(p+l, 2*READSTR-l, "ixcs: %ud %ud %ud\n", - ctlr->ixsm, ctlr->ipcs, ctlr->tcpcs); - l += snprint(p+l, 2*READSTR-l, "rdtr: %ud\n", ctlr->rdtr); - l += snprint(p+l, 2*READSTR-l, "radv: %ud\n", ctlr->radv); - l += snprint(p+l, 2*READSTR-l, "Ctrlext: %08x\n", csr32r(ctlr, Ctrlext)); - - l += snprint(p+l, 2*READSTR-l, "eeprom:"); - for(i = 0; i < 0x40; i++){ - if(i && ((i & 0x07) == 0)) - l += snprint(p+l, 2*READSTR-l, "\n "); - l += snprint(p+l, 2*READSTR-l, " %4.4uX", ctlr->eeprom[i]); - } - snprint(p+l, 2*READSTR-l, "\n"); - n = readstr(offset, a, n, p); - free(p); + p = seprint(p, e, "lintr: %ud %ud\n", ctlr->lintr, ctlr->lsleep); + p = seprint(p, e, "rintr: %ud %ud\n", ctlr->rintr, ctlr->rsleep); + p = seprint(p, e, "tintr: %ud %ud\n", ctlr->tintr, ctlr->txdw); + p = seprint(p, e, "ixcs: %ud %ud %ud\n", ctlr->ixsm, ctlr->ipcs, ctlr->tcpcs); + p = seprint(p, e, "rdtr: %ud\n", ctlr->rdtr); + p = seprint(p, e, "radv: %ud\n", ctlr->radv); + p = seprint(p, e, "ctrl: %.8ux\n", csr32r(ctlr, Ctrl)); + p = seprint(p, e, "ctrlext: %.8ux\n", csr32r(ctlr, Ctrlext)); + p = seprint(p, e, "status: %.8ux\n", csr32r(ctlr, Status)); + p = seprint(p, e, "txcw: %.8ux\n", csr32r(ctlr, Txcw)); + p = seprint(p, e, "txdctl: %.8ux\n", csr32r(ctlr, Txdctl)); + p = seprint(p, e, "pba: %.8ux\n", ctlr->pba); + + p = seprint(p, e, "speeds: 10:%ud 100:%ud 1000:%ud ?:%ud\n", + ctlr->speeds[0], ctlr->speeds[1], ctlr->speeds[2], ctlr->speeds[3]); + p = seprint(p, e, "type: %s\n", Type); + +// p = seprint(p, e, "eeprom:"); +// for(i = 0; i < 0x40; i++){ +// if(i && ((i & 0x07) == 0)) +// p = seprint(p, e, "\n "); +// p = seprint(p, e, " %4.4ux", ctlr->eeprom[i]); +// } +// p = seprint(p, e, "\n"); + + USED(p); + n = readstr(offset, a, n, s); + free(s); qunlock(&ctlr->slock); return n; @@ -626,7 +676,7 @@ if(v < 0 || p == cb->f[1] || v > 0xFFFF) error(Ebadarg); ctlr->rdtr = v; - csr32w(ctlr, Rdtr, Fpd|v); + csr32w(ctlr, Rdtr, v); break; case CMradv: v = strtol(cb->f[1], &p, 0); @@ -671,12 +721,14 @@ ctlr = edev->ctlr; x = addr[5]>>1; + if(ctlr->type == i82566) + x &= 31; bit = ((addr[5] & 1)<<4)|(addr[4]>>4); if(on) ctlr->mta[x] |= 1<mta[x] &= ~(1<mta[x]); } @@ -696,14 +748,12 @@ } static void -i82563rbfree(Block* bp) +i82563rbfree(Block* b) { - bp->rp = bp->lim - Rbsz; - bp->wp = bp->rp; - + b->rp = b->wp = (uchar*)PGROUND((uintptr)b->base); ilock(&i82563rblock); - bp->next = i82563rbpool; - i82563rbpool = bp; + b->next = i82563rbpool; + i82563rbpool = b; iunlock(&i82563rblock); } @@ -722,8 +772,8 @@ int i, r; Block *bp; - csr32w(ctlr, Tctl, (0x0F<tdba)); csr32w(ctlr, Tdbah, 0); csr32w(ctlr, Tdlen, ctlr->ntd*sizeof(Td)); @@ -742,12 +792,37 @@ csr32w(ctlr, Tidv, 128); r = csr32r(ctlr, Txdctl); r &= ~WthreshMASK; - r |= Gran|(4<type == i82671) +// csr32w(ctlr, Tarc0, csr32r(ctlr, Tarc0)|7<<24); /* yb sez? */ +} + +#define Next(x, m) (((x)+1)&(m)) + +static int +i82563cleanup(Ctlr *c) +{ + Block *b; + int tdh, m, n; + + tdh = c->tdh; + m = c->ntd-1; + while(c->tdba[n = Next(tdh, m)].status&Tdd){ + tdh = n; + if((b = c->tb[tdh]) != nil){ + c->tb[tdh] = nil; + freeb(b); + }else + iprint("82563 tx underrun!\n"); + c->tdba[tdh].status = 0; + } + + return c->tdh = tdh; } static void @@ -756,75 +831,69 @@ Td *td; Block *bp; Ctlr *ctlr; - int tdh, tdt, ctdh; + int tdh, tdt, m; ctlr = edev->ctlr; - ilock(&ctlr->tlock); + qlock(&ctlr->tlock); /* * Free any completed packets */ - tdh = ctlr->tdh; - ctdh = csr32r(ctlr, Tdh); - while(NEXT(tdh, ctlr->ntd) != ctdh){ - if((bp = ctlr->tb[tdh]) != nil){ - ctlr->tb[tdh] = nil; - freeb(bp); - } - memset(&ctlr->tdba[tdh], 0, sizeof(Td)); - tdh = NEXT(tdh, ctlr->ntd); - } - ctlr->tdh = tdh; + tdh = i82563cleanup(ctlr); /* * Try to fill the ring back up. */ tdt = ctlr->tdt; - while(NEXT(tdt, ctlr->ntd) != tdh){ + m = ctlr->ntd-1; + for(;;){ + if(Next(tdt, m) == tdh){ + ctlr->txdw++; + i82563im(ctlr, Txdw); + break; + } if((bp = qget(edev->oq)) == nil) break; td = &ctlr->tdba[tdt]; td->addr[0] = PCIWADDR(bp->rp); - td->control = ((BLEN(bp) & LenMASK)<control |= Ifcs|Teop|DtypeDD; + td->control = Ide|Rs|Ifcs|Teop|BLEN(bp); ctlr->tb[tdt] = bp; - tdt = NEXT(tdt, ctlr->ntd); + tdt = Next(tdt, m); + } + if(ctlr->tdt != tdt){ ctlr->tdt = tdt; - if(NEXT(tdt, ctlr->ntd) == tdh){ - td->control |= Rs; - ctlr->txdw++; - i82563im(ctlr, Txdw); - break; - } + csr32w(ctlr, Tdt, tdt); } - csr32w(ctlr, Tdt, tdt); - iunlock(&ctlr->tlock); + qunlock(&ctlr->tlock); } static void i82563replenish(Ctlr* ctlr) { Rd *rd; - int rdt; + int rdt, m; Block *bp; rdt = ctlr->rdt; - while(NEXT(rdt, ctlr->nrd) != ctlr->rdh){ + m = ctlr->nrd-1; + while(Next(rdt, m) != ctlr->rdh){ rd = &ctlr->rdba[rdt]; - if(ctlr->rb[rdt] == nil){ - bp = i82563rballoc(); - if(bp == nil){ - iprint("no available buffers\n"); - break; - } - ctlr->rb[rdt] = bp; - rd->addr[0] = PCIWADDR(bp->rp); - rd->addr[1] = 0; + if(ctlr->rb[rdt] != nil){ + iprint("82563 tx overrun\n"); + break; + } + bp = i82563rballoc(); + if(bp == nil){ + iprint("82563 no available buffers\n"); + break; } + ctlr->rb[rdt] = bp; + rd->addr[0] = PCIWADDR(bp->rp); +// rd->addr[1] = 0; rd->status = 0; - rdt = NEXT(rdt, ctlr->nrd); ctlr->rdfree++; + rdt = Next(rdt, m); } ctlr->rdt = rdt; csr32w(ctlr, Rdt, rdt); @@ -836,9 +905,23 @@ int i; Block *bp; -// csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF); -// csr32w(ctlr, Rctl, Lpe|Dpf|Bsize16384|Bam|RdtmsHALF|Bsex|Secrc); - csr32w(ctlr, Rctl, Lpe|Dpf|Bsize8192|Bam|RdtmsHALF|Bsex|Secrc); + if(ctlr->rbsz <= 2048) + csr32w(ctlr, Rctl, Dpf|Bsize2048|Bam|RdtmsHALF); + else if(ctlr->rbsz <= 8192) + csr32w(ctlr, Rctl, Lpe|Dpf|Bsize8192|Bsex|Bam|RdtmsHALF|Secrc); + else if(ctlr->rbsz <= 12*1024){ + i = ctlr->rbsz/1024; + if(ctlr->rbsz%1024) + i++; + csr32w(ctlr, Rctl, Lpe|Dpf|BsizeFlex*i|Bam|RdtmsHALF|Secrc); + }else + csr32w(ctlr, Rctl, Lpe|Dpf|Bsize16384|Bsex|Bam|RdtmsHALF|Secrc); + + if(ctlr->type == i82573) + csr32w(ctlr, Ert, 1024/8); + + if(ctlr->type == i82566) + csr32w(ctlr, Pbs, 16); csr32w(ctlr, Rdbal, PCIWADDR(ctlr->rdba)); csr32w(ctlr, Rdbah, 0); @@ -847,10 +930,10 @@ csr32w(ctlr, Rdh, 0); ctlr->rdt = 0; csr32w(ctlr, Rdt, 0); - ctlr->rdtr = 0; - ctlr->radv = 0; - csr32w(ctlr, Rdtr, Fpd|0); - csr32w(ctlr, Radv, 0); + ctlr->rdtr = 25; + ctlr->radv = 500; + csr32w(ctlr, Rdtr, ctlr->rdtr); + csr32w(ctlr, Radv, ctlr->radv); for(i = 0; i < ctlr->nrd; i++){ if((bp = ctlr->rb[i]) != nil){ @@ -859,10 +942,7 @@ } } i82563replenish(ctlr); - csr32w(ctlr, Radv, 64); -// csr32w(ctlr, Rxdctl, (8<ctlr; - rdh = ctlr->rdh; - for(;;){ - rd = &ctlr->rdba[rdh]; - - if(!(rd->status & Rdd)) - break; - - /* - * Accept eop packets with no errors. - * With no errors and the Ixsm bit set, - * the descriptor status Tpcs and Ipcs bits give - * an indication of whether the checksums were - * calculated and valid. - */ - if (bp = ctlr->rb[rdh]) { - if((rd->status & Reop) && rd->errors == 0){ - bp->wp += rd->length; - bp->next = nil; - if(!(rd->status & Ixsm)){ - ctlr->ixsm++; - if(rd->status & Ipcs){ - /* - * IP checksum calculated - * (and valid as errors == 0). - */ - ctlr->ipcs++; - bp->flag |= Bipck; - } - if(rd->status & Tcpcs){ - /* - * TCP/UDP checksum calculated - * (and valid as errors == 0). - */ - ctlr->tcpcs++; - bp->flag |= Btcpck|Budpck; - } - bp->checksum = rd->checksum; - bp->flag |= Bpktck; - } - etheriq(edev, bp, 1); - } else - freeb(bp); - ctlr->rb[rdh] = nil; - } - memset(rd, 0, sizeof(Rd)); - ctlr->rdfree--; - ctlr->rdh = rdh = NEXT(rdh, ctlr->nrd); - coherence(); - if(ctlr->rdfree < (ctlr->nrd/4)*3 || (ctlr->rim & Rxdmt0)) - i82563replenish(ctlr); - } -} - static int i82563rim(void* ctlr) { @@ -944,7 +962,7 @@ Rd *rd; Block *bp; Ctlr *ctlr; - int r, rdh, rim; + int r, m, rdh, rim; Ether *edev; edev = arg; @@ -954,11 +972,12 @@ r = csr32r(ctlr, Rctl); r |= Ren; csr32w(ctlr, Rctl, r); + m = ctlr->nrd-1; for(;;){ - i82563im(ctlr, Rxt0|Rxo|Rxdmt0|Rxseq); + i82563im(ctlr, Rxt0|Rxo|Rxdmt0|Rxseq|Ack); ctlr->rsleep++; - coherence(); +// coherence(); sleep(&ctlr->rrendez, i82563rim, ctlr); rdh = ctlr->rdh; @@ -968,7 +987,7 @@ ctlr->rim = 0; if(!(rd->status & Rdd)) break; - + /* * Accept eop packets with no errors. * With no errors and the Ixsm bit set, @@ -979,7 +998,6 @@ if (bp = ctlr->rb[rdh]) { if((rd->status & Reop) && rd->errors == 0){ bp->wp += rd->length; - bp->next = nil; if(!(rd->status & Ixsm)){ ctlr->ixsm++; if(rd->status & Ipcs){ @@ -1000,26 +1018,134 @@ } bp->checksum = rd->checksum; bp->flag |= Bpktck; + bp->lim = bp->wp; /* lie like a dog. */ } etheriq(edev, bp, 1); } else freeb(bp); ctlr->rb[rdh] = nil; } - memset(rd, 0, sizeof(Rd)); + rd->status = 0; ctlr->rdfree--; - ctlr->rdh = rdh = NEXT(rdh, ctlr->nrd); - coherence(); - if(ctlr->rdfree < (ctlr->nrd/4)*3 || (rim & Rxdmt0)) + ctlr->rdh = rdh = Next(rdh, m); + if(ctlr->nrd-ctlr->rdfree >= 32 || (rim & Rxdmt0)) i82563replenish(ctlr); } } } +static int +i82563lim(void* c) +{ + return ((Ctlr*)c)->lim != 0; +} + +static int speedtab[] = { + 10, 100, 1000, 0 +}; + +static uint +phyread(Ctlr *c, int reg) +{ + uint phy, i; + + csr32w(c, Mdic, MDIrop|(1<ctlr; + + phy = phyread(c, Phyier); + if(phy != ~0){ + phy |= 1<<14; + phywrite(c, Phyier, phy); + } + + for(;;){ + phy = phyread(c, Physsr); + if(phy == ~0) + goto next; + if(phy&Rtlink) + e->link = 1; + else + e->link = 0; + i = (phy>>14)&3; + + switch(c->type){ + case i82563: + if((phy&Phyan) == 0) + goto next; + break; + case i82571: + case i82572: + i = i-1&3; + break; + } + + c->speeds[i]++; + e->mbps = speedtab[i]; + next: + c->lim = 0; + i82563im(c, Lsc); + c->lsleep++; + sleep(&c->lrendez, i82563lim, c); + } +} + +static void +i82563tproc(void *v) +{ + Ether *e; + Ctlr *c; + + e = v; + c = e->ctlr; + + for(;;){ + sleep(&c->trendez, return0, 0); + i82563transmit(e); + } +} + static void i82563attach(Ether* edev) { - Block *bp, *fbp; + Block *bp; Ctlr *ctlr; char name[KNAMELEN]; @@ -1030,9 +1156,9 @@ return; } - ctlr->nrd = ROUND(Nrd, 8); - ctlr->ntd = ROUND(Ntd, 8); - ctlr->alloc = malloc(ctlr->nrd*sizeof(Rd)+ctlr->ntd*sizeof(Td) + 255); + ctlr->nrd = Nrd; + ctlr->ntd = Ntd; + ctlr->alloc = mallocz(ctlr->nrd*sizeof(Rd)+ctlr->ntd*sizeof(Td) + 255, 1); if(ctlr->alloc == nil){ qunlock(&ctlr->alock); return; @@ -1060,24 +1186,22 @@ nexterror(); } - fbp = nil; - for(ctlr->nrb = 0; ctlr->nrb < Nrb; ){ - if((bp = allocb(Rbsz)) == nil) + for(ctlr->nrb = 0; ctlr->nrb < Nrb; ctlr->nrb++){ + if((bp = allocb(ctlr->rbsz+BY2PG)) == nil) break; - if (((ulong)bp->base ^ (ulong)bp->lim) & ~0xffff) { - bp->next = fbp; - fbp = bp; - continue; - } bp->free = i82563rbfree; freeb(bp); - ctlr->nrb++; } - freeblist(fbp); + + snprint(name, KNAMELEN, "#l%dlproc", edev->ctlrno); + kproc(name, i82563lproc, edev); snprint(name, KNAMELEN, "#l%drproc", edev->ctlrno); kproc(name, i82563rproc, edev); + snprint(name, KNAMELEN, "#l%dtproc", edev->ctlrno); + kproc(name, i82563tproc, edev); + i82563txinit(ctlr); qunlock(&ctlr->alock); @@ -1089,7 +1213,7 @@ { Ctlr *ctlr; Ether *edev; - int icr, im, txdw; + int icr, im; edev = arg; ctlr = edev->ctlr; @@ -1097,7 +1221,6 @@ ilock(&ctlr->imlock); csr32w(ctlr, Imc, ~0); im = ctlr->im; - txdw = 0; while(icr = csr32r(ctlr, Icr) & ctlr->im){ if(icr & Lsc){ @@ -1106,26 +1229,22 @@ wakeup(&ctlr->lrendez); ctlr->lintr++; } - if(icr & (Rxt0|Rxo|Rxdmt0|Rxseq)){ - ctlr->rim = icr & (Rxt0|Rxo|Rxdmt0|Rxseq); - im &= ~(Rxt0|Rxo|Rxdmt0|Rxseq); + if(icr & (Rxt0|Rxo|Rxdmt0|Rxseq|Ack)){ + ctlr->rim = icr & (Rxt0|Rxo|Rxdmt0|Rxseq|Ack); + im &= ~(Rxt0|Rxo|Rxdmt0|Rxseq|Ack); wakeup(&ctlr->rrendez); -// i82563rcv(edev); ctlr->rintr++; } if(icr & Txdw){ im &= ~Txdw; - txdw++; ctlr->tintr++; + wakeup(&ctlr->trendez); } } ctlr->im = im; csr32w(ctlr, Ims, im); iunlock(&ctlr->imlock); - - if(txdw) - i82563transmit(edev); } static int @@ -1133,6 +1252,17 @@ { int r, timeo; + /* balance rx/tx packet buffer */ + if((ctlr->type == i82563 || ctlr->type == i82571 || ctlr->type == i82572) && ctlr->rbsz > 8192){ + ctlr->pba = csr32r(ctlr, Pba); + r = ctlr->pba>>16; + r += ctlr->pba&0xffff; + r >>= 1; + csr32w(ctlr, Pba, r); + } else if(ctlr->type == i82573 && ctlr->rbsz > 1514) + csr32w(ctlr, Pba, 14); + ctlr->pba = csr32r(ctlr, Pba); + /* * Perform a device reset to get the chip back to the * power-on state, followed by an EEPROM reset to read @@ -1144,7 +1274,10 @@ delay(10); - csr32w(ctlr, Ctrl, Devrst); + r = csr32r(ctlr, Ctrl); + if(ctlr->type == i82566) + r |= Phyrst; + csr32w(ctlr, Ctrl, Devrst|r); delay(1); for(timeo = 0; timeo < 1000; timeo++){ if(!(csr32r(ctlr, Ctrl) & Devrst)) @@ -1153,6 +1286,10 @@ } if(csr32r(ctlr, Ctrl) & Devrst) return -1; + + r = csr32r(ctlr, Ctrl); + csr32w(ctlr, Ctrl, Slu|r); + r = csr32r(ctlr, Ctrlext); csr32w(ctlr, Ctrlext, r|Eerst); delay(1); @@ -1197,7 +1334,7 @@ { ushort sum; int data, adr; - + sum = 0; for (adr = 0; adr < 0x40; adr++) { data = eeread(ctlr, adr); @@ -1207,45 +1344,6 @@ return sum; } -/* - * kind of unnecessary; - * but just in case they add 4 or 16 macs to the same ctlr. - */ -static uchar* -etheradd(uchar *u, uint n) -{ - int i; - uint j; - - for(i = 5; n != 0 && i >= 0; i--){ - j = n+u[i]; - u[i] = j; - n = j>>8; - } - return u; -} - -typedef struct { - uchar ea[Easize]; - int n; -} Basetab; - -static Basetab btab[Maxmac]; -static int nbase; - -int -nthether(uchar *ea) -{ - int i; - - for(i = 0; i < nelem(btab); i++) - if(btab[i].n == 0 || memcmp(btab[i].ea, ea, Easize) == 0) { - memmove(btab[i].ea, ea, Easize); - return btab[i].n++; - } - return -1; -} - static int i82563reset(Ctlr* ctlr) { @@ -1255,7 +1353,7 @@ return -1; r = eeload(ctlr); if (r != 0 && r != 0xBABA){ - print("i82563: bad EEPROM checksum - 0x%4.4uX\n", r); + print("%s: bad EEPROM checksum - %#.4ux\n", Type, r); return -1; } @@ -1263,7 +1361,8 @@ ctlr->ra[2*i] = ctlr->eeprom[i]; ctlr->ra[2*i+1] = ctlr->eeprom[i]>>8; } - etheradd(ctlr->ra, nthether(ctlr->ra)); + r = csr32r(ctlr, Status)>>2; + ctlr->ra[5] += r&3; /* ea ctlr[1] = ea ctlr[0]+1. */ r = (ctlr->ra[3]<<24)|(ctlr->ra[2]<<16)|(ctlr->ra[1]<<8)|ctlr->ra[0]; csr32w(ctlr, Ral, r); r = 0x80000000|(ctlr->ra[5]<<8)|ctlr->ra[4]; @@ -1281,39 +1380,61 @@ csr32w(ctlr, Fcttv, 0x00000100); csr32w(ctlr, Fcrtl, ctlr->fcrtl); csr32w(ctlr, Fcrth, ctlr->fcrth); + return 0; } static void i82563pci(void) { - int cls; + int cls, type; Pcidev *p; Ctlr *ctlr; ulong io; void *mem; p = nil; - while(p = pcimatch(p, 0, 0)){ - if(p->ccrb != Pcibcnet || p->ccru != 0) - continue; - if (p->vid != 0x8086 || p->did != 0x1096) + while(p = pcimatch(p, 0x8086, 0)){ + switch(p->did){ + default: continue; + case 0x1096: + case 0x10ba: + type = i82563; + break; + case 0x1049: /* mm */ + case 0x104a: /* dm */ + case 0x104d: /* v */ + type = i82566; + break; + case 0x10a4: + case 0x105e: + type = i82571; + break; + case 0x10b9: /* sic, 82572 */ + type = i82572; + break; + case 0x108b: /* e */ + case 0x108c: /* e (iamt) */ + case 0x109a: /* l */ + type = i82573; + break; + } io = p->mem[0].bar & ~0x0F; mem = vmap(io, p->mem[0].size); if(mem == nil){ - print("i82563: can't map %8.8luX\n", p->mem[0].bar); + print("%s: can't map %.8lux\n", tname[type], p->mem[0].bar); continue; } cls = pcicfgr8(p, PciCLS); switch(cls){ default: - print("i82563: unexpected CLS - %d\n", cls*4); + print("%s: unexpected CLS %d\n", tname[type], cls*4); break; case 0x00: case 0xFF: - print("i82563: unusable CLS\n"); + print("%s: unusable CLS\n", tname[type]); continue; case 0x08: case 0x10: @@ -1322,7 +1443,8 @@ ctlr = malloc(sizeof(Ctlr)); ctlr->port = io; ctlr->pcidev = p; - ctlr->id = (p->did<<16)|p->vid; + ctlr->type = type; + ctlr->rbsz = rbtab[type]; ctlr->cls = cls*4; ctlr->nic = mem; @@ -1341,7 +1463,7 @@ } static int -i82563pnp(Ether* edev) +pnp(Ether* edev, int type) { Ctlr *ctlr; @@ -1352,13 +1474,16 @@ * Any adapter matches if no edev->port is supplied, * otherwise the ports must match. */ - for(ctlr = i82563ctlrhead; ctlr != nil; ctlr = ctlr->next) + for(ctlr = i82563ctlrhead; ctlr != nil; ctlr = ctlr->next){ if(ctlr->active) continue; - else if(edev->port == 0 || edev->port == ctlr->port){ + if(ctlr->type != type) + continue; + if(edev->port == 0 || edev->port == ctlr->port){ ctlr->active = 1; break; } + } if(ctlr == nil) return -1; @@ -1367,7 +1492,7 @@ edev->irq = ctlr->pcidev->intl; edev->tbdf = ctlr->pcidev->tbdf; edev->mbps = 1000; - edev->maxmtu = Rbsz; + edev->maxmtu = ctlr->rbsz; memmove(edev->ea, ctlr->ra, Eaddrlen); /* @@ -1387,8 +1512,42 @@ return 0; } +static int +i82563pnp(Ether *e) +{ + return pnp(e, i82563); +} + +static int +i82566pnp(Ether *e) +{ + return pnp(e, i82566); +} + +static int +i82571pnp(Ether *e) +{ + return pnp(e, i82571); +} + +static int +i82572pnp(Ether *e) +{ + return pnp(e, i82572); +} + +static int +i82573pnp(Ether *e) +{ + return pnp(e, i82573); +} + void ether82563link(void) { addethercard("i82563", i82563pnp); + addethercard("i82566", i82566pnp); + addethercard("i82571", i82571pnp); + addethercard("i82572", i82572pnp); + addethercard("i82573", i82573pnp); }