ref: 39bf5b987e8ab53a74adec5a15b30f4eda85b357
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" int mii(Mii* mii, int mask) { MiiPhy *miiphy; int bit, oui, phyno, rmask; u32int id; /* * 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; id = mii->mir(mii, phyno, Phyidr1) << 16; id |= mii->mir(mii, phyno, Phyidr2); oui = (id & 0x3FFFFC00)>>10; if(oui == 0xFFFFF || oui == 0) continue; if((miiphy = malloc(sizeof(MiiPhy))) == nil) continue; miiphy->mii = mii; miiphy->id = id; 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); if(bmcr == -1) return -1; 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 == -1) return -1; 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); 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; } 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); if(mscr == -1) return -1; 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 == -1) return -1; if(r & Esr1000THD) mscr |= Mscr1000THD; if(r & Esr1000TFD) mscr |= Mscr1000TFD; } mii->curphy->mscr = mscr; mii->miw(mii, phyno, Mscr, mscr); } if(mii->miw(mii, phyno, Anar, anar) == -1) return -1; r = mii->mir(mii, phyno, Bmcr); if(r == -1) return -1; 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 == -1) return -1; if(!(bmsr & (BmsrAnc|BmsrAna))) { // print("miistatus: auto-neg incomplete\n"); return -1; } bmsr = mii->mir(mii, phyno, 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 = mii->mir(mii, phyno, 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 = mii->mir(mii, phyno, 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 miimmdr(Mii* mii, int a, int r) { a &= 0x1F; if(miimiw(mii, Mmdctrl, a) == -1) return -1; if(miimiw(mii, Mmddata, r) == -1) return -1; if(miimiw(mii, Mmdctrl, a | 0x4000) == -1) return -1; return miimir(mii, Mmddata); } int miimmdw(Mii* mii, int a, int r, int data) { a &= 0x1F; if(miimiw(mii, Mmdctrl, a) == -1) return -1; if(miimiw(mii, Mmddata, r) == -1) return -1; if(miimiw(mii, Mmdctrl, a | 0x4000) == -1) return -1; return miimiw(mii, Mmddata, data); }