summaryrefslogtreecommitdiffstats
path: root/sys/dev/bge
diff options
context:
space:
mode:
authorps <ps@FreeBSD.org>2003-05-03 19:06:50 +0000
committerps <ps@FreeBSD.org>2003-05-03 19:06:50 +0000
commitf6b6404d7f64bbdd5d2288c71cce10b084ac1090 (patch)
tree17617e195afebb5b466aea278f14db480648dab7 /sys/dev/bge
parent19105c8312c841631a5eff3408f8a43f4958e9ba (diff)
downloadFreeBSD-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.c87
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);
OpenPOWER on IntegriCloud