summaryrefslogtreecommitdiff
path: root/sys/dev/pci/if_bge.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/pci/if_bge.c')
-rw-r--r--sys/dev/pci/if_bge.c48
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) {