diff options
-rw-r--r-- | sys/dev/bge/if_bge.c | 87 | ||||
-rw-r--r-- | sys/dev/mii/brgphy.c | 181 |
2 files changed, 198 insertions, 70 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c index 3eb7b60..186726f 100644 --- a/sys/dev/bge/if_bge.c +++ b/sys/dev/bge/if_bge.c @@ -218,7 +218,6 @@ static int bge_miibus_writereg (device_t, int, int, int); static void bge_miibus_statchg (device_t); static void bge_reset (struct bge_softc *); -static void bge_phy_hack (struct bge_softc *); static device_method_t bge_methods[] = { /* Device interface */ @@ -477,7 +476,7 @@ bge_miibus_readreg(dev, phy, reg) { struct bge_softc *sc; struct ifnet *ifp; - u_int32_t val; + u_int32_t val, autopoll; int i; sc = device_get_softc(dev); @@ -491,6 +490,13 @@ bge_miibus_readreg(dev, phy, reg) return(0); } + /* Reading with autopolling on may trigger PCI errors */ + autopoll = CSR_READ_4(sc, BGE_MI_MODE); + if (autopoll & BGE_MIMODE_AUTOPOLL) { + BGE_CLRBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); + DELAY(40); + } + CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_READ|BGE_MICOMM_BUSY| BGE_MIPHY(phy)|BGE_MIREG(reg)); @@ -502,11 +508,18 @@ bge_miibus_readreg(dev, phy, reg) if (i == BGE_TIMEOUT) { printf("bge%d: PHY read timed out\n", sc->bge_unit); - return(0); + val = 0; + goto done; } val = CSR_READ_4(sc, BGE_MI_COMM); +done: + if (autopoll & BGE_MIMODE_AUTOPOLL) { + BGE_SETBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); + DELAY(40); + } + if (val & BGE_MICOMM_READFAIL) return(0); @@ -519,10 +532,18 @@ bge_miibus_writereg(dev, phy, reg, val) int phy, reg, val; { struct bge_softc *sc; + u_int32_t autopoll; int i; sc = device_get_softc(dev); + /* Reading with autopolling on may trigger PCI errors */ + autopoll = CSR_READ_4(sc, BGE_MI_MODE); + if (autopoll & BGE_MIMODE_AUTOPOLL) { + BGE_CLRBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); + DELAY(40); + } + CSR_WRITE_4(sc, BGE_MI_COMM, BGE_MICMD_WRITE|BGE_MICOMM_BUSY| BGE_MIPHY(phy)|BGE_MIREG(reg)|val); @@ -531,6 +552,11 @@ bge_miibus_writereg(dev, phy, reg, val) break; } + if (autopoll & BGE_MIMODE_AUTOPOLL) { + BGE_SETBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); + DELAY(40); + } + if (i == BGE_TIMEOUT) { printf("bge%d: PHY read timed out\n", sc->bge_unit); return(0); @@ -562,8 +588,6 @@ bge_miibus_statchg(dev) BGE_SETBIT(sc, BGE_MAC_MODE, BGE_MACMODE_HALF_DUPLEX); } - bge_phy_hack(sc); - return; } @@ -2029,14 +2053,20 @@ bge_intr(xsc) BRGPHY_INTRS); } } else { - if (sc->bge_rdata->bge_status_block.bge_status & - BGE_STATFLAG_LINKSTATE_CHANGED) { + if ((sc->bge_rdata->bge_status_block.bge_status & + BGE_STATFLAG_UPDATED) && + (sc->bge_rdata->bge_status_block.bge_status & + BGE_STATFLAG_LINKSTATE_CHANGED)) { + sc->bge_rdata->bge_status_block.bge_status &= ~(BGE_STATFLAG_UPDATED|BGE_STATFLAG_LINKSTATE_CHANGED); sc->bge_link = 0; untimeout(bge_tick, sc, sc->bge_stat_ch); bge_tick(sc); /* Clear the interrupt */ CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED| BGE_MACSTAT_CFG_CHANGED); + + /* Force flush the status block cached by PCI bridge */ + CSR_READ_4(sc, BGE_MBX_IRQ0_LO); } } @@ -2295,48 +2325,6 @@ bge_start(ifp) return; } -/* - * If we have a BCM5400 or BCM5401 PHY, we need to properly - * program its internal DSP. Failing to do this can result in - * massive packet loss at 1Gb speeds. - */ -static void -bge_phy_hack(sc) - struct bge_softc *sc; -{ - struct bge_bcom_hack bhack[] = { - { BRGPHY_MII_AUXCTL, 0x4C20 }, - { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, - { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, - { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, - { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, - { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, - { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, - { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, - { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, - { BRGPHY_MII_DSP_ADDR_REG, 0x201F }, - { BRGPHY_MII_DSP_RW_PORT, 0x0A20 }, - { 0, 0 } }; - u_int16_t vid, did; - int i; - - vid = bge_miibus_readreg(sc->bge_dev, 1, MII_PHYIDR1); - did = bge_miibus_readreg(sc->bge_dev, 1, MII_PHYIDR2); - - if (MII_OUI(vid, did) == MII_OUI_xxBROADCOM && - (MII_MODEL(did) == MII_MODEL_xxBROADCOM_BCM5400 || - MII_MODEL(did) == MII_MODEL_xxBROADCOM_BCM5401)) { - i = 0; - while(bhack[i].reg) { - bge_miibus_writereg(sc->bge_dev, 1, bhack[i].reg, - bhack[i].val); - i++; - } - } - - return; -} - static void bge_init(xsc) void *xsc; @@ -2474,7 +2462,6 @@ bge_ifmedia_upd(ifp) miisc = LIST_NEXT(miisc, mii_list)) mii_phy_reset(miisc); } - bge_phy_hack(sc); mii_mediachg(mii); return(0); diff --git a/sys/dev/mii/brgphy.c b/sys/dev/mii/brgphy.c index 49c4601..7f42688 100644 --- a/sys/dev/mii/brgphy.c +++ b/sys/dev/mii/brgphy.c @@ -82,6 +82,12 @@ DRIVER_MODULE(brgphy, miibus, brgphy_driver, brgphy_devclass, 0, 0); static int brgphy_service(struct mii_softc *, struct mii_data *, int); static void brgphy_status(struct mii_softc *); static int brgphy_mii_phy_auto(struct mii_softc *); +static void brgphy_reset(struct mii_softc *); +static void brgphy_loop(struct mii_softc *); +static void bcm5401_load_dspcode(struct mii_softc *); +static void bcm5411_load_dspcode(struct mii_softc *); +static void bcm5703_load_dspcode(struct mii_softc *); +static int brgphy_mii_model; static int brgphy_probe(dev) @@ -163,7 +169,8 @@ brgphy_attach(dev) BMCR_LOOP|BMCR_S100); #endif - mii_phy_reset(sc); + brgphy_mii_model = MII_MODEL(ma->mii_id2); + brgphy_reset(sc); sc->mii_capabilities = PHY_READ(sc, MII_BMSR) & ma->mii_capmask; @@ -193,7 +200,7 @@ brgphy_service(sc, mii, cmd) int cmd; { struct ifmedia_entry *ife = mii->mii_media.ifm_cur; - int reg, speed; + int reg, speed, gig; switch (cmd) { case MII_POLLSTAT: @@ -221,11 +228,7 @@ brgphy_service(sc, mii, cmd) if ((mii->mii_ifp->if_flags & IFF_UP) == 0) break; - PHY_WRITE(sc, BRGPHY_MII_PHY_EXTCTL, - BRGPHY_PHY_EXTCTL_HIGH_LA|BRGPHY_PHY_EXTCTL_EN_LTR); - PHY_WRITE(sc, BRGPHY_MII_AUXCTL, - BRGPHY_AUXCTL_LONG_PKT|BRGPHY_AUXCTL_TX_TST); - PHY_WRITE(sc, BRGPHY_MII_IMR, 0xFF00); + brgphy_reset(sc); /* XXX hardware bug work-around */ switch (IFM_SUBTYPE(ife->ifm_media)) { case IFM_AUTO: @@ -247,15 +250,26 @@ brgphy_service(sc, mii, cmd) case IFM_10_T: speed = BRGPHY_S10; setit: + brgphy_loop(sc); if ((ife->ifm_media & IFM_GMASK) == IFM_FDX) { - PHY_WRITE(sc, BRGPHY_MII_BMCR, - BRGPHY_BMCR_FDX|speed); + speed |= BRGPHY_BMCR_FDX; + gig = BRGPHY_1000CTL_AFD; } else { - PHY_WRITE(sc, BRGPHY_MII_BMCR, speed); + gig = BRGPHY_1000CTL_AHD; } + + PHY_WRITE(sc, BRGPHY_MII_1000CTL, 0); + PHY_WRITE(sc, BRGPHY_MII_BMCR, speed); PHY_WRITE(sc, BRGPHY_MII_ANAR, BRGPHY_SEL_TYPE); - if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) + if (IFM_SUBTYPE(ife->ifm_media) != IFM_1000_T) + break; + + PHY_WRITE(sc, BRGPHY_MII_1000CTL, gig); + PHY_WRITE(sc, BRGPHY_MII_BMCR, + speed|BRGPHY_BMCR_AUTOEN|BRGPHY_BMCR_STARTNEG); + + if (brgphy_mii_model != MII_MODEL_xxBROADCOM_BCM5701) break; /* @@ -268,10 +282,10 @@ setit: */ if ((mii->mii_ifp->if_flags & IFF_LINK0)) { PHY_WRITE(sc, BRGPHY_MII_1000CTL, - BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC); + gig|BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC); } else { PHY_WRITE(sc, BRGPHY_MII_1000CTL, - BRGPHY_1000CTL_MSE); + gig|BRGPHY_1000CTL_MSE); } break; #ifdef foo @@ -320,7 +334,6 @@ setit: return (0); sc->mii_ticks = 0; - mii_phy_reset(sc); brgphy_mii_phy_auto(sc); return (0); } @@ -402,12 +415,12 @@ brgphy_mii_phy_auto(mii) { int ktcr = 0; - mii_phy_reset(mii); - PHY_WRITE(mii, BRGPHY_MII_BMCR, 0); - DELAY(1000); - ktcr = PHY_READ(mii, BRGPHY_MII_1000CTL); - PHY_WRITE(mii, BRGPHY_MII_1000CTL, ktcr | - BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD); + brgphy_loop(mii); + brgphy_reset(mii); + ktcr = BRGPHY_1000CTL_AFD|BRGPHY_1000CTL_AHD; + if (brgphy_mii_model == MII_MODEL_xxBROADCOM_BCM5701) + ktcr |= BRGPHY_1000CTL_MSE|BRGPHY_1000CTL_MSC; + PHY_WRITE(mii, BRGPHY_MII_1000CTL, ktcr); ktcr = PHY_READ(mii, BRGPHY_MII_1000CTL); DELAY(1000); PHY_WRITE(mii, BRGPHY_MII_ANAR, @@ -418,3 +431,131 @@ brgphy_mii_phy_auto(mii) PHY_WRITE(mii, BRGPHY_MII_IMR, 0xFF00); return (EJUSTRETURN); } + +static void +brgphy_loop(struct mii_softc *sc) +{ + u_int32_t bmsr; + int i; + + PHY_WRITE(sc, BRGPHY_MII_BMCR, BRGPHY_BMCR_LOOP); + for (i = 0; i < 15000; i++) { + bmsr = PHY_READ(sc, BRGPHY_MII_BMSR); + if (!(bmsr & BRGPHY_BMSR_LINK)) { +#if 0 + device_printf(sc->mii_dev, "looped %d\n", i); +#endif + break; + } + DELAY(10); + } +} + +/* Turn off tap power management on 5401. */ +static void +bcm5401_load_dspcode(struct mii_softc *sc) +{ + static const struct { + int reg; + uint16_t val; + } dspcode[] = { + { BRGPHY_MII_AUXCTL, 0x0c20 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x0012 }, + { BRGPHY_MII_DSP_RW_PORT, 0x1804 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x0013 }, + { BRGPHY_MII_DSP_RW_PORT, 0x1204 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, + { BRGPHY_MII_DSP_RW_PORT, 0x0132 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x8006 }, + { BRGPHY_MII_DSP_RW_PORT, 0x0232 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, + { BRGPHY_MII_DSP_RW_PORT, 0x0a20 }, + { 0, 0 }, + }; + int i; + + for (i = 0; dspcode[i].reg != 0; i++) + PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); + DELAY(40); +} + +static void +bcm5411_load_dspcode(struct mii_softc *sc) +{ + static const struct { + int reg; + uint16_t val; + } dspcode[] = { + { 0x1c, 0x8c23 }, + { 0x1c, 0x8ca3 }, + { 0x1c, 0x8c23 }, + { 0, 0 }, + }; + int i; + + for (i = 0; dspcode[i].reg != 0; i++) + PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); +} + +static void +bcm5703_load_dspcode(struct mii_softc *sc) +{ + static const struct { + int reg; + uint16_t val; + } dspcode[] = { + { BRGPHY_MII_AUXCTL, 0x0c00 }, + { BRGPHY_MII_DSP_ADDR_REG, 0x201f }, + { BRGPHY_MII_DSP_RW_PORT, 0x2aaa }, + { 0, 0 }, + }; + int i; + + for (i = 0; dspcode[i].reg != 0; i++) + PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); +} + +static void +bcm5704_load_dspcode(struct mii_softc *sc) +{ + static const struct { + int reg; + u_int16_t val; + } dspcode[] = { + { 0x1c, 0x8d68 }, + { 0x1c, 0x8d68 }, + { 0, 0 }, + }; + int i; + + for (i = 0; dspcode[i].reg != 0; i++) + PHY_WRITE(sc, dspcode[i].reg, dspcode[i].val); +} + +static void +brgphy_reset(struct mii_softc *sc) +{ + u_int32_t val; + + mii_phy_reset(sc); + + switch (brgphy_mii_model) { + case MII_MODEL_xxBROADCOM_BCM5401: + bcm5401_load_dspcode(sc); + break; + case MII_MODEL_xxBROADCOM_BCM5411: + bcm5411_load_dspcode(sc); + break; + case MII_MODEL_xxBROADCOM_BCM5703: + bcm5703_load_dspcode(sc); + break; + case MII_MODEL_xxBROADCOM_BCM5704: + bcm5704_load_dspcode(sc); + break; + } + + /* Enable Ethernet@WireSpeed. */ + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, 0x7007); + val = PHY_READ(sc, BRGPHY_MII_AUXCTL); + PHY_WRITE(sc, BRGPHY_MII_AUXCTL, val | (1 << 15) || (1 << 4)); +} |