diff options
author | ps <ps@FreeBSD.org> | 2003-05-03 19:06:50 +0000 |
---|---|---|
committer | ps <ps@FreeBSD.org> | 2003-05-03 19:06:50 +0000 |
commit | f6b6404d7f64bbdd5d2288c71cce10b084ac1090 (patch) | |
tree | 17617e195afebb5b466aea278f14db480648dab7 /sys/dev/bge | |
parent | 19105c8312c841631a5eff3408f8a43f4958e9ba (diff) | |
download | FreeBSD-src-f6b6404d7f64bbdd5d2288c71cce10b084ac1090.zip FreeBSD-src-f6b6404d7f64bbdd5d2288c71cce10b084ac1090.tar.gz |
- Move bge_phy_hack into the phy code and implement the various DSP
patch workarounds for each phy revision.
Obtained from: NetBSD & Broadcom Linux driver
- Disable AUTOPOLL when accessing the PHY as it may cause PCI errors.
Obtained from: NetBSD
- Check the UPDATED bit in the status block so the driver knows
that the status block as indeed changed since the last access.
Broadcom documentation states drivers should unset the UPDATED/CHANGED
bits after reading them.
- When changing media types, first loop the phy then set the media.
Broadcom documentation and Linux drivers do this and I observed
much better handling of link after this change.
- Broadcom documentation states that for 1000BaseT operation,
autonegotiation must be enabled. Fix hard coding of media so that
the driver only advertises 1000BaseT as the supported media type
and enable autonegotition.
- Only set Master/Slave on the 5701.
Obtained from Broadcom Linux driver.
Diffstat (limited to 'sys/dev/bge')
-rw-r--r-- | sys/dev/bge/if_bge.c | 87 |
1 files changed, 37 insertions, 50 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); |