diff options
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) { |