diff options
author | Stuart Henderson <sthen@cvs.openbsd.org> | 2008-02-20 10:26:54 +0000 |
---|---|---|
committer | Stuart Henderson <sthen@cvs.openbsd.org> | 2008-02-20 10:26:54 +0000 |
commit | 42d50285dc0534294fbf138324bb71ceee907c35 (patch) | |
tree | a3c77cb366aeec323957646a48bf575a716ee80f /sys/dev | |
parent | 678bf240f29628a0fd2fa1f4cb45592eb764e007 (diff) |
when bge has link, use autopolling for link status, not direct mii polls.
fixes input errors on BCM5701/5702X/5704 and may avoid firmware hangs on
some cards if asf/ipmi support is added.
original diff from Oleg Bulyzhin in a freebsd-net post and ported by
mickey; included stats counter changes which don't apply to -current
so they are split out and not included here. "The rest of the diff
looks ok" brad.
tested on 5701/5702X/5703X/5704C/5721 by mpf naddy okan beck sthen
ok beck (before splitting out stats changes), krw, henning.
closes kernel/5699
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_bge.c | 70 | ||||
-rw-r--r-- | sys/dev/pci/if_bgereg.h | 11 |
2 files changed, 52 insertions, 29 deletions
diff --git a/sys/dev/pci/if_bge.c b/sys/dev/pci/if_bge.c index c7a8dba6074..feeb3ecfe21 100644 --- a/sys/dev/pci/if_bge.c +++ b/sys/dev/pci/if_bge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bge.c,v 1.220 2008/02/18 09:40:11 brad Exp $ */ +/* $OpenBSD: if_bge.c,v 1.221 2008/02/20 10:26:53 sthen Exp $ */ /* * Copyright (c) 2001 Wind River Systems @@ -586,6 +586,7 @@ bge_miibus_readreg(struct device *dev, int phy, int reg) /* Reading with autopolling on may trigger PCI errors */ autopoll = CSR_READ_4(sc, BGE_MI_MODE); if (autopoll & BGE_MIMODE_AUTOPOLL) { + BGE_STS_CLRBIT(sc, BGE_STS_AUTOPOLL); BGE_CLRBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); DELAY(40); } @@ -611,6 +612,7 @@ bge_miibus_readreg(struct device *dev, int phy, int reg) done: if (autopoll & BGE_MIMODE_AUTOPOLL) { + BGE_STS_SETBIT(sc, BGE_STS_AUTOPOLL); BGE_SETBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); DELAY(40); } @@ -632,6 +634,7 @@ bge_miibus_writereg(struct device *dev, int phy, int reg, int val) autopoll = CSR_READ_4(sc, BGE_MI_MODE); if (autopoll & BGE_MIMODE_AUTOPOLL) { DELAY(40); + BGE_STS_CLRBIT(sc, BGE_STS_AUTOPOLL); BGE_CLRBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); DELAY(10); /* 40 usec is supposed to be adequate */ } @@ -647,6 +650,7 @@ bge_miibus_writereg(struct device *dev, int phy, int reg, int val) } if (autopoll & BGE_MIMODE_AUTOPOLL) { + BGE_STS_SETBIT(sc, BGE_STS_AUTOPOLL); BGE_SETBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL); DELAY(40); } @@ -1718,6 +1722,7 @@ bge_blockinit(struct bge_softc *sc) if (sc->bge_flags & BGE_PHY_FIBER_TBI) { CSR_WRITE_4(sc, BGE_MI_STS, BGE_MISTS_LINK); } else { + BGE_STS_SETBIT(sc, BGE_STS_AUTOPOLL); BGE_SETBIT(sc, BGE_MI_MODE, BGE_MIMODE_AUTOPOLL|10<<16); if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700 && sc->bge_chipid != BGE_CHIPID_BCM5700_B2) @@ -2646,7 +2651,7 @@ bge_intr(void *xsc) if ((BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700 && sc->bge_chipid != BGE_CHIPID_BCM5700_B2) || statusword & BGE_STATFLAG_LINKSTATE_CHANGED || - sc->bge_link_evt) + BGE_STS_BIT(sc, BGE_STS_LINK_EVT)) bge_link_upd(sc); if (ifp->if_flags & IFF_RUNNING) { @@ -2687,10 +2692,17 @@ bge_tick(void *xsc) * link status manually. Here we register pending link event * and trigger interrupt. */ - sc->bge_link_evt++; + BGE_STS_SETBIT(sc, BGE_STS_LINK_EVT); BGE_SETBIT(sc, BGE_MISC_LOCAL_CTL, BGE_MLC_INTR_SET); - } else - mii_tick(mii); + } else { + /* + * Do not touch PHY if we have link up. This could break + * IPMI/ASF mode or produce extra input errors. + * (extra input errors was reported for bcm5701 & bcm5704). + */ + if (!BGE_STS_BIT(sc, BGE_STS_LINK)) + mii_tick(mii); + } timeout_add(&sc->bge_timeout, hz); @@ -2963,7 +2975,7 @@ bge_start(struct ifnet *ifp) if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) return; - if (!sc->bge_link) + if (!BGE_STS_BIT(sc, BGE_STS_LINK)) return; if (IFQ_IS_EMPTY(&ifp->if_snd)) return; @@ -3172,7 +3184,7 @@ bge_ifmedia_upd(struct ifnet *ifp) return (0); } - sc->bge_link_evt++; + BGE_STS_SETBIT(sc, BGE_STS_LINK_EVT); if (mii->mii_instance) { struct mii_softc *miisc; LIST_FOREACH(miisc, &mii->mii_phys, mii_list) @@ -3445,7 +3457,7 @@ bge_stop(struct bge_softc *sc) * lead to hardware deadlock. So we just clearing MAC's link state * (PHY may still have link UP). */ - sc->bge_link = 0; + BGE_STS_CLRBIT(sc, BGE_STS_LINK); } /* @@ -3466,10 +3478,11 @@ bge_link_upd(struct bge_softc *sc) { struct ifnet *ifp = &sc->arpcom.ac_if; struct mii_data *mii = &sc->bge_mii; - u_int32_t link, status; + u_int32_t status; + int link; /* Clear 'pending link event' flag */ - sc->bge_link_evt = 0; + BGE_STS_CLRBIT(sc, BGE_STS_LINK_EVT); /* * Process link state changes. @@ -3493,14 +3506,14 @@ bge_link_upd(struct bge_softc *sc) timeout_del(&sc->bge_timeout); bge_tick(sc); - if (!sc->bge_link && + if (!BGE_STS_BIT(sc, BGE_STS_LINK) && mii->mii_media_status & IFM_ACTIVE && IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { - sc->bge_link++; - } else if (sc->bge_link && + BGE_STS_SETBIT(sc, BGE_STS_LINK); + } else if (BGE_STS_BIT(sc, BGE_STS_LINK) && (!(mii->mii_media_status & IFM_ACTIVE) || IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE)) { - sc->bge_link = 0; + BGE_STS_CLRBIT(sc, BGE_STS_LINK); } /* Clear the interrupt */ @@ -3516,8 +3529,8 @@ bge_link_upd(struct bge_softc *sc) if (sc->bge_flags & BGE_PHY_FIBER_TBI) { status = CSR_READ_4(sc, BGE_MAC_STS); if (status & BGE_MACSTAT_TBI_PCS_SYNCHED) { - if (!sc->bge_link) { - sc->bge_link++; + if (!BGE_STS_BIT(sc, BGE_STS_LINK)) { + BGE_STS_SETBIT(sc, BGE_STS_LINK); if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5704) BGE_CLRBIT(sc, BGE_MAC_MODE, BGE_MACMODE_TBI_SEND_CFGS); @@ -3529,33 +3542,38 @@ bge_link_upd(struct bge_softc *sc) LINK_STATE_FULL_DUPLEX; if_link_state_change(ifp); } - } else if (sc->bge_link) { - sc->bge_link = 0; + } else if (BGE_STS_BIT(sc, BGE_STS_LINK)) { + BGE_STS_CLRBIT(sc, BGE_STS_LINK); ifp->if_link_state = LINK_STATE_DOWN; if_link_state_change(ifp); } - /* Discard link events for MII/GMII cards if MI auto-polling disabled */ - } else if (CSR_READ_4(sc, BGE_MI_MODE) & BGE_MIMODE_AUTOPOLL) { + /* + * Discard link events for MII/GMII cards if MI auto-polling disabled. + * This should not happen since mii callouts are locked now, but + * we keep this check for debug. + */ + } else if (BGE_STS_BIT(sc, BGE_STS_AUTOPOLL)) { /* * Some broken BCM chips have BGE_STATFLAG_LINKSTATE_CHANGED bit * in status word always set. Workaround this bug by reading * PHY link status directly. */ - link = (CSR_READ_4(sc, BGE_MI_STS) & BGE_MISTS_LINK) ? 1 : 0; + link = (CSR_READ_4(sc, BGE_MI_STS) & BGE_MISTS_LINK)? + BGE_STS_LINK : 0; - if (link != sc->bge_link || + if (BGE_STS_BIT(sc, BGE_STS_LINK) != link || BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700) { timeout_del(&sc->bge_timeout); bge_tick(sc); - if (!sc->bge_link && + if (!BGE_STS_BIT(sc, BGE_STS_LINK) && mii->mii_media_status & IFM_ACTIVE && IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) - sc->bge_link++; - else if (sc->bge_link && + BGE_STS_SETBIT(sc, BGE_STS_LINK); + else if (BGE_STS_BIT(sc, BGE_STS_LINK) && (!(mii->mii_media_status & IFM_ACTIVE) || IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE)) - sc->bge_link = 0; + BGE_STS_CLRBIT(sc, BGE_STS_LINK); } } diff --git a/sys/dev/pci/if_bgereg.h b/sys/dev/pci/if_bgereg.h index ba66309c63f..078d6de392b 100644 --- a/sys/dev/pci/if_bgereg.h +++ b/sys/dev/pci/if_bgereg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bgereg.h,v 1.78 2008/02/18 09:40:11 brad Exp $ */ +/* $OpenBSD: if_bgereg.h,v 1.79 2008/02/20 10:26:53 sthen Exp $ */ /* * Copyright (c) 2001 Wind River Systems @@ -2465,11 +2465,16 @@ struct bge_softc { u_int32_t bge_rx_max_coal_bds; u_int32_t bge_tx_max_coal_bds; u_int32_t bge_tx_buf_ratio; + u_int32_t bge_sts; +#define BGE_STS_LINK 0x00000001 /* MAC link status */ +#define BGE_STS_LINK_EVT 0x00000002 /* pending link event */ +#define BGE_STS_AUTOPOLL 0x00000004 /* PHY auto-polling */ +#define BGE_STS_BIT(sc, x) ((sc)->bge_sts & (x)) +#define BGE_STS_SETBIT(sc, x) ((sc)->bge_sts |= (x)) +#define BGE_STS_CLRBIT(sc, x) ((sc)->bge_sts &= ~(x)) int bge_flowflags; int bge_if_flags; int bge_txcnt; - int bge_link; /* link state */ - int bge_link_evt; /* pending link event */ struct timeout bge_timeout; void *sc_powerhook; void *sc_shutdownhook; |