on some machines with 8169 lom, gbe link would not happen unless the machine was pxe booted. the solution is to kick in autonegotiation, and wait for it. if the timing's just right, we'll miss the link status. also, we'd like to size the queues correctly the first time. also, thanks to pavel, we use 16 bits for the cplusc register. sadly the reason this came up is a hard problem to solve. when 100mbps and 1000mbps machines are plugged together, ip fragment resending will usually drop the same parts of the packet, so resending does no good. Reference: /n/atom/patch/applied/8169gbe Date: Fri Jun 20 00:53:04 CES 2014 Signed-off-by: quanstro@quanstro.net --- /sys/src/nix/k10/ether8169.c Fri Jun 20 00:47:28 2014 +++ /sys/src/nix/k10/ether8169.c Fri Jun 20 00:47:30 2014 @@ -229,10 +229,10 @@ Ntd = 64, /* Transmit Ring */ Nrd = 256, /* Receive Ring */ - Stdbuf = 1536, - Mtu = 7000, /* performance limited */ - Mps = Mtu + 8 + 14, /* if(mtu>ETHERMAXTU) */ -// Mps = ROUNDUP(ETHERMAXTU+4, 128), +// Mtu = 7000, /* performance limited */ +// Mps = Mtu + 8 + 14, /* if(mtu>ETHERMAXTU) */ + Mtu = 1536, + Mps = ROUNDUP(ETHERMAXTU+4, 128), }; typedef struct Dtcc Dtcc; @@ -393,6 +393,7 @@ static Mii* rtl8169mii(Ctlr* ctlr) { + int i; Mii* mii; MiiPhy *phy; @@ -419,9 +420,16 @@ dprint("oui %#ux phyno %d, macv = %#8.8ux phyv = %#4.4ux\n", phy->oui, phy->phyno, ctlr->macv, ctlr->phyv); - if(miistatus(mii) < 0){ + if(miistatus(mii) < 0 || mii->curphy->speed < 1000){ miireset(mii); miiane(mii, ~0, ~0, ~0); + + /* try to bring the link up here */ + for(i = 0; i < 350; i += 1){ + if(miistatus(ctlr->mii) == 0) + break; + delay(1); + } } return mii; @@ -582,6 +590,7 @@ p = seprint(p, e, "tcr: %#8.8ux\n", ctlr->tcr); p = seprint(p, e, "rcr: %#8.8ux\n", ctlr->rcr); p = seprint(p, e, "multicast: %ud\n", ctlr->mcast); + p = seprint(p, e, "macv: %.8ux\n", ctlr->macv); if(ctlr->mii != nil && ctlr->mii->curphy != nil) miidumpphy(ctlr->mii, p, e); @@ -598,6 +607,7 @@ static void rtl8169halt(Ctlr* ctlr) { + csr32w(ctlr, Timerint, 0); csr8w(ctlr, Cr, 0); csr16w(ctlr, Imr, 0); csr16w(ctlr, Isr, ~0); @@ -675,7 +685,7 @@ u32int r; Block *bp; Ctlr *ctlr; - u8int cplusc; + u16int cplusc; ctlr = edev->ctlr; ilock(&ctlr->ilock); @@ -850,12 +860,9 @@ static void rtl8169attach(Ether* edev) { - int timeo, firsta; Ctlr *ctlr; - MiiPhy *phy; ctlr = edev->ctlr; - firsta = 0; qlock(&ctlr->alock); if(ctlr->init == 0){ /* @@ -870,23 +877,8 @@ ctlr->dtcc = mallocalign(sizeof(Dtcc), 64, 0, 0); rtl8169init(edev); ctlr->init = 1; - firsta = 1; } qunlock(&ctlr->alock); - - /* - * Wait for link to be ready. why here? - */ - if(firsta){ - for(timeo = 0; timeo < 350; timeo += 10){ - if(miistatus(ctlr->mii) == 0) - break; - tsleep(&up->sleep, return0, 0, 10); - } - phy = ctlr->mii->curphy; - dprint("%s: speed %d fd %d link %d rfc %d tfc %d\n", - edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc); - } } static void @@ -907,7 +899,7 @@ phy = ctlr->mii->curphy; if(miistatus(ctlr->mii) < 0){ - dprint("%slink n: speed %d fd %d link %d rfc %d tfc %d\n", + dprint("%s: link n: speed %d fd %d link %d rfc %d tfc %d\n", edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc); edev->link = 0; @@ -924,7 +916,7 @@ edev->mbps = 100; else if(phy->speed == 1000) edev->mbps = 1000; - dprint("%slink y: speed %d fd %d link %d rfc %d tfc %d\n", + dprint("%s: link y: speed %d fd %d link %d rfc %d tfc %d\n", edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc); @@ -1111,6 +1103,28 @@ } } +static long +rtl8169ctl(Ether *e, void *buf, long n) +{ + Cmdbuf *cb; + + cb = parsecmd(buf, n); + if(waserror()){ + free(cb); + nexterror(); + } + if(cb->nf == 1 && strcmp(cb->f[0], "debug") == 0) + debug ^= 1; + if(cb->nf == 1 && strcmp(cb->f[0], "link") == 0) + rtl8169link(e); + else + cmderror(cb, "unknown"); + free(cb); + poperror(); + + return n; +} + int vetmacv(Ctlr *ctlr, uint *macv) { @@ -1157,7 +1171,7 @@ continue; pcie = 0; - switch(i = ((p->did<<16)|p->vid)){ + switch(i = (p->did<<16|p->vid)){ default: continue; case Rtl8100e: /* RTL810[01]E ? */ @@ -1269,6 +1283,7 @@ break; default: edev->maxmtu = Mtu; + break; } /* @@ -1291,6 +1306,7 @@ edev->transmit = rtl8169transmit; edev->interrupt = rtl8169interrupt; edev->ifstat = rtl8169ifstat; + edev->ctl = rtl8169ctl; edev->arg = edev; edev->promiscuous = rtl8169promiscuous; --- /sys/src/9/pc/ether8169.c Fri Jun 20 00:47:32 2014 +++ /sys/src/9/pc/ether8169.c Fri Jun 20 00:47:35 2014 @@ -229,10 +229,10 @@ Ntd = 64, /* Transmit Ring */ Nrd = 256, /* Receive Ring */ - Stdbuf = 1536, - Mtu = 7000, /* performance limited */ - Mps = Mtu + 8 + 14, /* if(mtu>ETHERMAXTU) */ -// Mps = ROUNDUP(ETHERMAXTU+4, 128), +// Mtu = 7000, /* performance limited */ +// Mps = Mtu + 8 + 14, /* if(mtu>ETHERMAXTU) */ + Mtu = 1536, + Mps = ROUNDUP(ETHERMAXTU+4, 128), }; typedef struct Dtcc Dtcc; @@ -393,6 +393,7 @@ static Mii* rtl8169mii(Ctlr* ctlr) { + int i; Mii* mii; MiiPhy *phy; @@ -419,9 +420,16 @@ dprint("oui %#ux phyno %d, macv = %#8.8ux phyv = %#4.4ux\n", phy->oui, phy->phyno, ctlr->macv, ctlr->phyv); - if(miistatus(mii) < 0){ + if(miistatus(mii) < 0 || mii->curphy->speed < 1000){ miireset(mii); miiane(mii, ~0, ~0, ~0); + + /* try to bring the link up here */ + for(i = 0; i < 350; i += 1){ + if(miistatus(ctlr->mii) == 0) + break; + delay(1); + } } return mii; @@ -582,6 +590,7 @@ p = seprint(p, e, "tcr: %#8.8ux\n", ctlr->tcr); p = seprint(p, e, "rcr: %#8.8ux\n", ctlr->rcr); p = seprint(p, e, "multicast: %ud\n", ctlr->mcast); + p = seprint(p, e, "macv: %.8ux\n", ctlr->macv); if(ctlr->mii != nil && ctlr->mii->curphy != nil) miidumpphy(ctlr->mii, p, e); @@ -598,6 +607,7 @@ static void rtl8169halt(Ctlr* ctlr) { + csr32w(ctlr, Timerint, 0); csr8w(ctlr, Cr, 0); csr16w(ctlr, Imr, 0); csr16w(ctlr, Isr, ~0); @@ -675,7 +685,7 @@ u32int r; Block *bp; Ctlr *ctlr; - u8int cplusc; + u16int cplusc; ctlr = edev->ctlr; ilock(&ctlr->ilock); @@ -850,12 +860,9 @@ static void rtl8169attach(Ether* edev) { - int timeo, firsta; Ctlr *ctlr; - MiiPhy *phy; ctlr = edev->ctlr; - firsta = 0; qlock(&ctlr->alock); if(ctlr->init == 0){ /* @@ -870,23 +877,8 @@ ctlr->dtcc = mallocalign(sizeof(Dtcc), 64, 0, 0); rtl8169init(edev); ctlr->init = 1; - firsta = 1; } qunlock(&ctlr->alock); - - /* - * Wait for link to be ready. why here? - */ - if(firsta){ - for(timeo = 0; timeo < 350; timeo += 10){ - if(miistatus(ctlr->mii) == 0) - break; - tsleep(&up->sleep, return0, 0, 10); - } - phy = ctlr->mii->curphy; - dprint("%s: speed %d fd %d link %d rfc %d tfc %d\n", - edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc); - } } static void @@ -907,7 +899,7 @@ phy = ctlr->mii->curphy; if(miistatus(ctlr->mii) < 0){ - dprint("%slink n: speed %d fd %d link %d rfc %d tfc %d\n", + dprint("%s: link n: speed %d fd %d link %d rfc %d tfc %d\n", edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc); edev->link = 0; @@ -924,7 +916,7 @@ edev->mbps = 100; else if(phy->speed == 1000) edev->mbps = 1000; - dprint("%slink y: speed %d fd %d link %d rfc %d tfc %d\n", + dprint("%s: link y: speed %d fd %d link %d rfc %d tfc %d\n", edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc); @@ -1111,6 +1103,28 @@ } } +static long +rtl8169ctl(Ether *e, void *buf, long n) +{ + Cmdbuf *cb; + + cb = parsecmd(buf, n); + if(waserror()){ + free(cb); + nexterror(); + } + if(cb->nf == 1 && strcmp(cb->f[0], "debug") == 0) + debug ^= 1; + if(cb->nf == 1 && strcmp(cb->f[0], "link") == 0) + rtl8169link(e); + else + cmderror(cb, "unknown"); + free(cb); + poperror(); + + return n; +} + int vetmacv(Ctlr *ctlr, uint *macv) { @@ -1157,7 +1171,7 @@ continue; pcie = 0; - switch(i = ((p->did<<16)|p->vid)){ + switch(i = (p->did<<16|p->vid)){ default: continue; case Rtl8100e: /* RTL810[01]E ? */ @@ -1269,6 +1283,7 @@ break; default: edev->maxmtu = Mtu; + break; } /* @@ -1291,6 +1306,7 @@ edev->transmit = rtl8169transmit; edev->interrupt = rtl8169interrupt; edev->ifstat = rtl8169ifstat; + edev->ctl = rtl8169ctl; edev->arg = edev; edev->promiscuous = rtl8169promiscuous; --- /sys/src/9/pcpae/ether8169.c Fri Jun 20 00:47:38 2014 +++ /sys/src/9/pcpae/ether8169.c Fri Jun 20 00:47:40 2014 @@ -229,10 +229,10 @@ Ntd = 64, /* Transmit Ring */ Nrd = 256, /* Receive Ring */ - Stdbuf = 1536, - Mtu = 7000, /* performance limited */ - Mps = Mtu + 8 + 14, /* if(mtu>ETHERMAXTU) */ -// Mps = ROUNDUP(ETHERMAXTU+4, 128), +// Mtu = 7000, /* performance limited */ +// Mps = Mtu + 8 + 14, /* if(mtu>ETHERMAXTU) */ + Mtu = 1536, + Mps = ROUNDUP(ETHERMAXTU+4, 128), }; typedef struct Dtcc Dtcc; @@ -393,6 +393,7 @@ static Mii* rtl8169mii(Ctlr* ctlr) { + int i; Mii* mii; MiiPhy *phy; @@ -419,9 +420,16 @@ dprint("oui %#ux phyno %d, macv = %#8.8ux phyv = %#4.4ux\n", phy->oui, phy->phyno, ctlr->macv, ctlr->phyv); - if(miistatus(mii) < 0){ + if(miistatus(mii) < 0 || mii->curphy->speed < 1000){ miireset(mii); miiane(mii, ~0, ~0, ~0); + + /* try to bring the link up here */ + for(i = 0; i < 350; i += 1){ + if(miistatus(ctlr->mii) == 0) + break; + delay(1); + } } return mii; @@ -582,6 +590,7 @@ p = seprint(p, e, "tcr: %#8.8ux\n", ctlr->tcr); p = seprint(p, e, "rcr: %#8.8ux\n", ctlr->rcr); p = seprint(p, e, "multicast: %ud\n", ctlr->mcast); + p = seprint(p, e, "macv: %.8ux\n", ctlr->macv); if(ctlr->mii != nil && ctlr->mii->curphy != nil) miidumpphy(ctlr->mii, p, e); @@ -598,6 +607,7 @@ static void rtl8169halt(Ctlr* ctlr) { + csr32w(ctlr, Timerint, 0); csr8w(ctlr, Cr, 0); csr16w(ctlr, Imr, 0); csr16w(ctlr, Isr, ~0); @@ -675,7 +685,7 @@ u32int r; Block *bp; Ctlr *ctlr; - u8int cplusc; + u16int cplusc; ctlr = edev->ctlr; ilock(&ctlr->ilock); @@ -850,12 +860,9 @@ static void rtl8169attach(Ether* edev) { - int timeo, firsta; Ctlr *ctlr; - MiiPhy *phy; ctlr = edev->ctlr; - firsta = 0; qlock(&ctlr->alock); if(ctlr->init == 0){ /* @@ -870,23 +877,8 @@ ctlr->dtcc = mallocalign(sizeof(Dtcc), 64, 0, 0); rtl8169init(edev); ctlr->init = 1; - firsta = 1; } qunlock(&ctlr->alock); - - /* - * Wait for link to be ready. why here? - */ - if(firsta){ - for(timeo = 0; timeo < 350; timeo += 10){ - if(miistatus(ctlr->mii) == 0) - break; - tsleep(&up->sleep, return0, 0, 10); - } - phy = ctlr->mii->curphy; - dprint("%s: speed %d fd %d link %d rfc %d tfc %d\n", - edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc); - } } static void @@ -907,7 +899,7 @@ phy = ctlr->mii->curphy; if(miistatus(ctlr->mii) < 0){ - dprint("%slink n: speed %d fd %d link %d rfc %d tfc %d\n", + dprint("%s: link n: speed %d fd %d link %d rfc %d tfc %d\n", edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc); edev->link = 0; @@ -924,7 +916,7 @@ edev->mbps = 100; else if(phy->speed == 1000) edev->mbps = 1000; - dprint("%slink y: speed %d fd %d link %d rfc %d tfc %d\n", + dprint("%s: link y: speed %d fd %d link %d rfc %d tfc %d\n", edev->name, phy->speed, phy->fd, phy->link, phy->rfc, phy->tfc); @@ -1111,6 +1103,28 @@ } } +static long +rtl8169ctl(Ether *e, void *buf, long n) +{ + Cmdbuf *cb; + + cb = parsecmd(buf, n); + if(waserror()){ + free(cb); + nexterror(); + } + if(cb->nf == 1 && strcmp(cb->f[0], "debug") == 0) + debug ^= 1; + if(cb->nf == 1 && strcmp(cb->f[0], "link") == 0) + rtl8169link(e); + else + cmderror(cb, "unknown"); + free(cb); + poperror(); + + return n; +} + int vetmacv(Ctlr *ctlr, uint *macv) { @@ -1157,7 +1171,7 @@ continue; pcie = 0; - switch(i = ((p->did<<16)|p->vid)){ + switch(i = (p->did<<16|p->vid)){ default: continue; case Rtl8100e: /* RTL810[01]E ? */ @@ -1269,6 +1283,7 @@ break; default: edev->maxmtu = Mtu; + break; } /* @@ -1291,6 +1306,7 @@ edev->transmit = rtl8169transmit; edev->interrupt = rtl8169interrupt; edev->ifstat = rtl8169ifstat; + edev->ctl = rtl8169ctl; edev->arg = edev; edev->promiscuous = rtl8169promiscuous;