ref: 0a6bcc7b83d9b5fac12229cac57207b9dc91ba2f
dir: /sys/src/9/port/ethermii.c/
#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 "../port/etherif.h" #include "ethermii.h" /* hook for devmii */ static void dummy(Mii*){} void (*addmiibus)(Mii*) = dummy; void (*delmiibus)(Mii*) = dummy; uint mii(Mii* mii, uint mask) { MiiPhy *phy; int oui, phyno; uint bit, rmask, id; qlock(mii); if(up != nil && waserror()){ qunlock(mii); nexterror(); } /* * 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 = 1U<<phyno; if(!(mask & bit)) continue; if(mii->mask & bit){ rmask |= bit; continue; } if((*mii->mir)(mii, phyno, Bmsr) == -1) continue; id = (*mii->mir)(mii, phyno, Phyidr1) << 16; id |= (*mii->mir)(mii, phyno, Phyidr2); oui = (id & 0x3FFFFC00)>>10; if(oui == 0xFFFFF || oui == 0) continue; if((phy = malloc(sizeof(MiiPhy))) == nil) continue; phy->mii = mii; phy->id = id; phy->oui = oui; phy->phyno = phyno; phy->anar = ~0; phy->fc = ~0; phy->mscr = ~0; mii->phy[phyno] = phy; if(mii->curphy == nil) mii->curphy = phy; mii->mask |= bit; mii->nphy++; rmask |= bit; } qunlock(mii); if(up != nil) poperror(); return rmask; } int miimir(MiiPhy *phy, int r) { Mii *mii; int ret; if(phy == nil || (mii = phy->mii) == nil) return -1; qlock(mii); if(up != nil && waserror()){ qunlock(mii); nexterror(); } ret = (*mii->mir)(mii, phy->phyno, r & 0x1F); qunlock(mii); if(up != nil) poperror(); return ret; } int miimiw(MiiPhy *phy, int r, int data) { Mii *mii; int ret; if(phy == nil || (mii = phy->mii) == nil) return -1; qlock(mii); if(up != nil && waserror()){ qunlock(mii); nexterror(); } ret = (*mii->miw)(mii, phy->phyno, r & 0x1F, data & 0xFFFF); qunlock(mii); if(up != nil) poperror(); return ret; } int miireset(MiiPhy *phy) { int bmcr; bmcr = miimir(phy, Bmcr); if(bmcr == -1) return -1; bmcr |= BmcrR; miimiw(phy, Bmcr, bmcr); microdelay(1); return 0; } int miiane(MiiPhy *phy, int a, int p, int e) { int anar, bmsr, mscr, r; bmsr = miimir(phy, Bmsr); if(bmsr == -1) return -1; if(!(bmsr & BmsrAna)) return -1; if(a != ~0) anar = (AnaTXFD|AnaTXHD|Ana10FD|Ana10HD) & a; else if(phy->anar != ~0) anar = phy->anar; else{ anar = miimir(phy, Anar); if(anar == -1) return -1; 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; } phy->anar = anar; if(p != ~0) anar |= (AnaAP|AnaP) & p; else if(phy->fc != ~0) anar |= phy->fc; phy->fc = (AnaAP|AnaP) & anar; if(bmsr & BmsrEs){ mscr = miimir(phy, Mscr); if(mscr == -1) return -1; mscr &= ~(Mscr1000TFD|Mscr1000THD); if(e != ~0) mscr |= (Mscr1000TFD|Mscr1000THD) & e; else if(phy->mscr != ~0) mscr = phy->mscr; else{ r = miimir(phy, Esr); if(r == -1) return -1; if(r & Esr1000THD) mscr |= Mscr1000THD; if(r & Esr1000TFD) mscr |= Mscr1000TFD; } phy->mscr = mscr; miimiw(phy, Mscr, mscr); } if(miimiw(phy, Anar, anar) == -1) return -1; r = miimir(phy, Bmcr); if(r == -1) return -1; if(!(r & BmcrR)){ r |= BmcrAne|BmcrRan; miimiw(phy, Bmcr, r); } return 0; } int miianec45(MiiPhy* phy, int m) { int r; phy->mgcr = m; phy->mgcr &= (MMDanmgcr2500T|MMDanmgcr5000T|MMDanmgcr10000T); r = miimmdr(phy, MMDan, MMDanmgcr); if (r == -1) return -1; r &= ~phy->mgcr; r |= phy->mgcr; if (miimmdw(phy, MMDan, MMDanmgcr, r) == -1) return -1; return 0; } int miistatus(MiiPhy* phy) { int anlpar, bmsr, p, r; /* * Check Auto-Negotiation is complete and link is up. * (Read status twice as the Ls bit is sticky). */ bmsr = miimir(phy, Bmsr); if(bmsr == -1) return -1; if(!(bmsr & (BmsrAnc|BmsrAna))) { // print("miistatus: auto-neg incomplete\n"); return -1; } bmsr = miimir(phy, Bmsr); if(bmsr == -1) return -1; 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 = miimir(phy, Mssr); if(r == -1) return -1; if((phy->mscr & Mscr1000TFD) && (r & Mssr1000TFD)){ phy->speed = 1000; phy->fd = 1; } else if((phy->mscr & Mscr1000THD) && (r & Mssr1000THD)) phy->speed = 1000; } anlpar = miimir(phy, Anlpar); if(anlpar == -1) return -1; 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; } int miistatusc45(MiiPhy *phy) { int r; r = miimmdr(phy, MMDan, MMDanmgsr); if (r == -1) return -1; if (r & MMDanmgsr2500T) { phy->speed = 2500; phy->fd = 1; } if (r & MMDanmgsr5000T) { phy->speed = 5000; phy->fd = 1; } if (r & MMDanmgsr10000T) { phy->speed = 10000; phy->fd = 1; } return 0; } int miimmdr(MiiPhy *phy, int a, int r) { Mii *mii; int ret; if(phy == nil || (mii = phy->mii) == nil) return -1; qlock(mii); if(up != nil && waserror()){ qunlock(mii); nexterror(); } a &= 0x1F; if((ret = (*mii->miw)(mii, phy->phyno, Mmdctrl, a)) == -1) goto out; if((ret = (*mii->miw)(mii, phy->phyno, Mmddata, r & 0xFFFF)) == -1) goto out; if((ret = (*mii->miw)(mii, phy->phyno, Mmdctrl, a | 0x4000)) == -1) goto out; ret = (*mii->mir)(mii, phy->phyno, Mmddata); out: qunlock(mii); if(up != nil) poperror(); return ret; } int miimmdw(MiiPhy *phy, int a, int r, int data) { Mii *mii; int ret; if(phy == nil || (mii = phy->mii) == nil) return -1; qlock(mii); if(up != nil && waserror()){ qunlock(mii); nexterror(); } a &= 0x1F; if((ret = (*mii->miw)(mii, phy->phyno, Mmdctrl, a)) == -1) goto out; if((ret = (*mii->miw)(mii, phy->phyno, Mmddata, r & 0xFFFF)) == -1) goto out; if((ret = (*mii->miw)(mii, phy->phyno, Mmdctrl, a | 0x4000)) == -1) goto out; ret = (*mii->miw)(mii, phy->phyno, Mmddata, data & 0xFFFF); out: qunlock(mii); if(up != nil) poperror(); return ret; }