diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/pc/ethermii.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/pc/ethermii.c')
-rwxr-xr-x | sys/src/9/pc/ethermii.c | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/sys/src/9/pc/ethermii.c b/sys/src/9/pc/ethermii.c new file mode 100755 index 000000000..90b219b3f --- /dev/null +++ b/sys/src/9/pc/ethermii.c @@ -0,0 +1,235 @@ +#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" + +int +mii(Mii* mii, int mask) +{ + MiiPhy *miiphy; + int bit, oui, phyno, r, rmask; + + /* + * Probe through mii for PHYs in mask; + * return the mask of those found in the current probe. + * If the PHY has not already been probed, update + * the Mii information. + */ + rmask = 0; + for(phyno = 0; phyno < NMiiPhy; phyno++){ + bit = 1<<phyno; + if(!(mask & bit)) + continue; + if(mii->mask & bit){ + rmask |= bit; + continue; + } + if(mii->mir(mii, phyno, Bmsr) == -1) + continue; + r = mii->mir(mii, phyno, Phyidr1); + oui = (r & 0x3FFF)<<6; + r = mii->mir(mii, phyno, Phyidr2); + oui |= r>>10; + if(oui == 0xFFFFF || oui == 0) + continue; + + if((miiphy = malloc(sizeof(MiiPhy))) == nil) + continue; + + miiphy->mii = mii; + miiphy->oui = oui; + miiphy->phyno = phyno; + + miiphy->anar = ~0; + miiphy->fc = ~0; + miiphy->mscr = ~0; + + mii->phy[phyno] = miiphy; + if(mii->curphy == nil) + mii->curphy = miiphy; + mii->mask |= bit; + mii->nphy++; + + rmask |= bit; + } + return rmask; +} + +int +miimir(Mii* mii, int r) +{ + if(mii == nil || mii->ctlr == nil || mii->curphy == nil) + return -1; + return mii->mir(mii, mii->curphy->phyno, r); +} + +int +miimiw(Mii* mii, int r, int data) +{ + if(mii == nil || mii->ctlr == nil || mii->curphy == nil) + return -1; + return mii->miw(mii, mii->curphy->phyno, r, data); +} + +int +miireset(Mii* mii) +{ + int bmcr; + + if(mii == nil || mii->ctlr == nil || mii->curphy == nil) + return -1; + bmcr = mii->mir(mii, mii->curphy->phyno, Bmcr); + bmcr |= BmcrR; + mii->miw(mii, mii->curphy->phyno, Bmcr, bmcr); + microdelay(1); + + return 0; +} + +int +miiane(Mii* mii, int a, int p, int e) +{ + int anar, bmsr, mscr, r, phyno; + + if(mii == nil || mii->ctlr == nil || mii->curphy == nil) + return -1; + phyno = mii->curphy->phyno; + + bmsr = mii->mir(mii, phyno, Bmsr); + if(!(bmsr & BmsrAna)) + return -1; + + if(a != ~0) + anar = (AnaTXFD|AnaTXHD|Ana10FD|Ana10HD) & a; + else if(mii->curphy->anar != ~0) + anar = mii->curphy->anar; + else{ + anar = mii->mir(mii, phyno, Anar); + anar &= ~(AnaAP|AnaP|AnaT4|AnaTXFD|AnaTXHD|Ana10FD|Ana10HD); + if(bmsr & Bmsr10THD) + anar |= Ana10HD; + if(bmsr & Bmsr10TFD) + anar |= Ana10FD; + if(bmsr & Bmsr100TXHD) + anar |= AnaTXHD; + if(bmsr & Bmsr100TXFD) + anar |= AnaTXFD; + } + mii->curphy->anar = anar; + + if(p != ~0) + anar |= (AnaAP|AnaP) & p; + else if(mii->curphy->fc != ~0) + anar |= mii->curphy->fc; + mii->curphy->fc = (AnaAP|AnaP) & anar; + + if(bmsr & BmsrEs){ + mscr = mii->mir(mii, phyno, Mscr); + mscr &= ~(Mscr1000TFD|Mscr1000THD); + if(e != ~0) + mscr |= (Mscr1000TFD|Mscr1000THD) & e; + else if(mii->curphy->mscr != ~0) + mscr = mii->curphy->mscr; + else{ + r = mii->mir(mii, phyno, Esr); + if(r & Esr1000THD) + mscr |= Mscr1000THD; + if(r & Esr1000TFD) + mscr |= Mscr1000TFD; + } + mii->curphy->mscr = mscr; + mii->miw(mii, phyno, Mscr, mscr); + } + mii->miw(mii, phyno, Anar, anar); + + r = mii->mir(mii, phyno, Bmcr); + if(!(r & BmcrR)){ + r |= BmcrAne|BmcrRan; + mii->miw(mii, phyno, Bmcr, r); + } + + return 0; +} + +int +miistatus(Mii* mii) +{ + MiiPhy *phy; + int anlpar, bmsr, p, r, phyno; + + if(mii == nil || mii->ctlr == nil || mii->curphy == nil) + return -1; + phy = mii->curphy; + phyno = phy->phyno; + + /* + * Check Auto-Negotiation is complete and link is up. + * (Read status twice as the Ls bit is sticky). + */ + bmsr = mii->mir(mii, phyno, Bmsr); + if(!(bmsr & (BmsrAnc|BmsrAna))) { + // print("miistatus: auto-neg incomplete\n"); + return -1; + } + + bmsr = mii->mir(mii, phyno, Bmsr); + if(!(bmsr & BmsrLs)){ + // print("miistatus: link down\n"); + phy->link = 0; + return -1; + } + + phy->speed = phy->fd = phy->rfc = phy->tfc = 0; + if(phy->mscr){ + r = mii->mir(mii, phyno, Mssr); + if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){ + phy->speed = 1000; + phy->fd = 1; + } + else if((phy->mscr & Mscr1000THD) && (r & Mssr1000THD)) + phy->speed = 1000; + } + + anlpar = mii->mir(mii, phyno, Anlpar); + if(phy->speed == 0){ + r = phy->anar & anlpar; + if(r & AnaTXFD){ + phy->speed = 100; + phy->fd = 1; + } + else if(r & AnaTXHD) + phy->speed = 100; + else if(r & Ana10FD){ + phy->speed = 10; + phy->fd = 1; + } + else if(r & Ana10HD) + phy->speed = 10; + } + if(phy->speed == 0) { + // print("miistatus: phy speed 0\n"); + return -1; + } + + if(phy->fd){ + p = phy->fc; + r = anlpar & (AnaAP|AnaP); + if(p == AnaAP && r == (AnaAP|AnaP)) + phy->tfc = 1; + else if(p == (AnaAP|AnaP) && r == AnaAP) + phy->rfc = 1; + else if((p & AnaP) && (r & AnaP)) + phy->rfc = phy->tfc = 1; + } + + phy->link = 1; + + return 0; +} |