diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2004-11-11 18:35:42 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2004-11-11 18:35:42 +0000 |
commit | 2c014094006603d350781ecea9ce928bea15c211 (patch) | |
tree | 9516faa55a9c1594dd19a7bb0a794359be8889a3 /sys/dev/pci/if_bge.c | |
parent | 5c62f76e555a2114a0d1bc67c5dc80d0bf1d5036 (diff) |
rev 1.71
Add some special case code to fix a problem with the BCM5704 in TBI (fiber)
mode. The 5704 apparently has some s00p3r s33kr1t registers for setting
the advertisement of pause frame ability (i.e flow control) when in
autoneg mode. If we don't set these registers correctly, we may not
be able to negotiate a proper link with some switches. (Symptom is that
the NIC reports the link as up (PCS synched) but no traffic can be
exchanged.)
rev 1.73
Commit patch to supress spurious link change events. Apparently, with
copper NICs, a link change event is posted whenever MII autopolling is
toggled off and on, which happens whenever someone calls
bge_miibus_readreg() or bge_miibus_writereg() to access the PHY
registers. This means anytime someone called the SIOCGIFMEDIA ioctl
on a bge interface, the link would reset. Even a simple "ifconfig bge0"
would do it, though other apps like dhclient or the PPPoE daemon could
trigger it as well. An obvious symptom of this problem is lots of
"bgeX: gigabit link up" messages appearing on the console for no
apparent reason.
Through experimentation, I determined that when a real link change
event occurs, the BGE_MIMODE_AUTOPOLL in the BGE_MI_MODE register
is always set, so now if we have a copper NIC and an link change
event occurs and the BGE_MIMODE_AUTOPOLL bit is clear, we ignore
the event.
Note that this does not apply to the original BCM5700 chip since we
use a different method for sensing link changes with that chip (the
status block method was broken), nor to fiber optic NICs since they
don't use the GMII PHY access registers.
From FreeBSD
ok deraadt@
Diffstat (limited to 'sys/dev/pci/if_bge.c')
-rw-r--r-- | sys/dev/pci/if_bge.c | 48 |
1 files changed, 45 insertions, 3 deletions
diff --git a/sys/dev/pci/if_bge.c b/sys/dev/pci/if_bge.c index 11d06ca2f53..2a0add69a1f 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.34 2004/10/31 06:59:25 brad Exp $ */ +/* $OpenBSD: if_bge.c,v 1.35 2004/11/11 18:35:41 brad Exp $ */ /* * Copyright (c) 2001 Wind River Systems * Copyright (c) 1997, 1998, 1999, 2001 @@ -1769,6 +1769,7 @@ bge_attach(parent, self, aux) 0, NULL); ifmedia_add(&sc->bge_ifmedia, IFM_ETHER|IFM_AUTO, 0, NULL); ifmedia_set(&sc->bge_ifmedia, IFM_ETHER|IFM_AUTO); + sc->bge_ifmedia.ifm_media = sc->bge_ifmedia.ifm_cur->ifm_media; } else { /* * Do transceiver setup. @@ -1956,6 +1957,18 @@ bge_reset(sc) CSR_WRITE_4(sc, BGE_MAC_MODE, 0); + /* + * The 5704 in TBI mode apparently needs some special + * adjustment to insure the SERDES drive level is set + * to 1.2V. + */ + if (sc->bge_asicrev == BGE_ASICREV_BCM5704 && sc->bge_tbi) { + uint32_t serdescfg; + serdescfg = CSR_READ_4(sc, BGE_SERDES_CFG); + serdescfg = (serdescfg & ~0xFFF) | 0x880; + CSR_WRITE_4(sc, BGE_SERDES_CFG, serdescfg); + } + /* XXX: Broadcom Linux driver. */ if (sc->bge_pcie && sc->bge_chipid != BGE_CHIPID_BCM5750_A0) { uint32_t v; @@ -2155,7 +2168,7 @@ bge_intr(xsc) { struct bge_softc *sc; struct ifnet *ifp; - u_int32_t status; + u_int32_t status, mimode; sc = xsc; ifp = &sc->arpcom.ac_if; @@ -2213,10 +2226,19 @@ bge_intr(xsc) * that sometimes appear on fiber NICs during * periods of heavy traffic. (There should be no * effect on copper NICs). + * + * If we do have a copper NIC (bge_tbi == 0) then + * check that the AUTOPOLL bit is set before + * processing the event as a real link change. + * Turning AUTOPOLL on and off in the MII read/write + * functions will often trigger a link status + * interrupt for no reason. */ status = CSR_READ_4(sc, BGE_MAC_STS); + mimode = CSR_READ_4(sc, BGE_MI_MODE); if (!(status & (BGE_MACSTAT_PORT_DECODE_ERROR | - BGE_MACSTAT_MI_COMPLETE))) { + BGE_MACSTAT_MI_COMPLETE)) && (!sc->bge_tbi && + (mimode & BGE_MIMODE_AUTOPOLL))) { sc->bge_link = 0; timeout_del(&sc->bge_timeout); bge_tick(sc); @@ -2278,6 +2300,9 @@ bge_tick(xsc) if (CSR_READ_4(sc, BGE_MAC_STS) & BGE_MACSTAT_TBI_PCS_SYNCHED) { sc->bge_link++; + if (sc->bge_asicrev == BGE_ASICREV_BCM5704) + BGE_CLRBIT(sc, BGE_MAC_MODE, + BGE_MACMODE_TBI_SEND_CFGS); CSR_WRITE_4(sc, BGE_MAC_STS, 0xFFFFFFFF); if (!IFQ_IS_EMPTY(&ifp->if_snd)) bge_start(ifp); @@ -2655,6 +2680,23 @@ bge_ifmedia_upd(ifp) return(EINVAL); switch(IFM_SUBTYPE(ifm->ifm_media)) { case IFM_AUTO: + /* + * The BCM5704 ASIC appears to have a special + * mechanism for programming the autoneg + * advertisement registers in TBI mode. + */ + if (sc->bge_asicrev == BGE_ASICREV_BCM5704) { + uint32_t sgdig; + CSR_WRITE_4(sc, BGE_TX_TBI_AUTONEG, 0); + sgdig = CSR_READ_4(sc, BGE_SGDIG_CFG); + sgdig |= BGE_SGDIGCFG_AUTO| + BGE_SGDIGCFG_PAUSE_CAP| + BGE_SGDIGCFG_ASYM_PAUSE; + CSR_WRITE_4(sc, BGE_SGDIG_CFG, + sgdig|BGE_SGDIGCFG_SEND); + DELAY(5); + CSR_WRITE_4(sc, BGE_SGDIG_CFG, sgdig); + } break; case IFM_1000_SX: if ((ifm->ifm_media & IFM_GMASK) == IFM_FDX) { |