summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/bge/if_bge.c87
-rw-r--r--sys/dev/mii/brgphy.c181
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));
+}
OpenPOWER on IntegriCloud