Hi, While trying to fix the link state bug on BCM5719, David Imhoff has arrived at conclusion that the chip won't generate proper link state interrupts which renders auto-polling mode useless.
As it turns out neither Linux nor FreeBSD use auto-polling mode for anything newer than BCM5705 and recent Broadcom documentation is not describing this method at all. This diff brings us in line with others, but requires heavy testing on currently supported hardware. OK's are welcome as well. diff --git sys/dev/pci/if_bge.c sys/dev/pci/if_bge.c index 1d37192..8007108 100644 --- sys/dev/pci/if_bge.c +++ sys/dev/pci/if_bge.c @@ -1055,10 +1055,22 @@ bge_miibus_statchg(struct device *dev) (mii->mii_media_active & IFM_ETH_FMASK) != sc->bge_flowflags) { sc->bge_flowflags = mii->mii_media_active & IFM_ETH_FMASK; mii->mii_media_active &= ~IFM_ETH_FMASK; } + if (!BGE_STS_BIT(sc, BGE_STS_LINK) && + mii->mii_media_status & IFM_ACTIVE && + IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) + 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)) + BGE_STS_CLRBIT(sc, BGE_STS_LINK); + + if (!BGE_STS_BIT(sc, BGE_STS_LINK)) + return; + /* Set the port mode (MII/GMII) to match the link speed. */ mac_mode = CSR_READ_4(sc, BGE_MAC_MODE) & ~(BGE_MACMODE_PORTMODE | BGE_MACMODE_HALF_DUPLEX); tx_mode = CSR_READ_4(sc, BGE_TX_MODE); rx_mode = CSR_READ_4(sc, BGE_RX_MODE); @@ -1773,11 +1785,11 @@ int bge_blockinit(struct bge_softc *sc) { volatile struct bge_rcb *rcb; vaddr_t rcb_addr; bge_hostaddr taddr; - u_int32_t dmactl, val; + u_int32_t dmactl, mimode, val; int i, limit; /* * Initialize the memory window pointer register so that * we can access the first 32K of internal NIC RAM. This will @@ -2369,13 +2381,23 @@ bge_blockinit(struct bge_softc *sc) /* Enable PHY auto polling (for MII/GMII only) */ 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) + if ((sc->bge_flags & BGE_CPMU_PRESENT) != 0) + mimode = BGE_MIMODE_500KHZ_CONST; + else + mimode = BGE_MIMODE_BASE; + if (BGE_IS_5700_FAMILY(sc) || + BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5705) { + mimode |= BGE_MIMODE_AUTOPOLL; + BGE_STS_SETBIT(sc, BGE_STS_AUTOPOLL); + } + mimode |= BGE_MIMODE_PHYADDR(sc->bge_phy_addr); + CSR_WRITE_4(sc, BGE_MI_MODE, mimode); + if (BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5700 && + sc->bge_chipid != BGE_CHIPID_BCM5700_B2) CSR_WRITE_4(sc, BGE_MAC_EVT_ENB, BGE_EVTENB_MI_INTERRUPT); } /* @@ -2719,13 +2741,10 @@ bge_attach(struct device *parent, struct device *self, void *aux) BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5761 || BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM5785 || BGE_ASICREV(sc->bge_chipid) == BGE_ASICREV_BCM57780) sc->bge_flags |= BGE_CPMU_PRESENT; - if ((sc->bge_flags & BGE_CPMU_PRESENT) != 0) - BGE_SETBIT(sc, BGE_MI_MODE, BGE_MIMODE_500KHZ_CONST); - /* Try to reset the chip. */ DPRINTFN(5, ("bge_reset\n")); bge_sig_pre_reset(sc, BGE_RESET_START); bge_reset(sc); @@ -4489,15 +4508,10 @@ bge_link_upd(struct bge_softc *sc) BGE_STS_CLRBIT(sc, BGE_STS_LINK); ifp->if_link_state = LINK_STATE_DOWN; if_link_state_change(ifp); ifp->if_baudrate = 0; } - /* - * 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. @@ -4515,10 +4529,17 @@ bge_link_upd(struct bge_softc *sc) else if (BGE_STS_BIT(sc, BGE_STS_LINK) && (!(mii->mii_media_status & IFM_ACTIVE) || IFM_SUBTYPE(mii->mii_media_active) == IFM_NONE)) BGE_STS_CLRBIT(sc, BGE_STS_LINK); } + } else { + /* + * For controllers that call mii_tick, we have to poll + * link status. + */ + mii_pollstat(mii); + bge_miibus_statchg(&sc->bge_dev); } /* Clear the attention */ CSR_WRITE_4(sc, BGE_MAC_STS, BGE_MACSTAT_SYNC_CHANGED| BGE_MACSTAT_CFG_CHANGED|BGE_MACSTAT_MI_COMPLETE| diff --git sys/dev/pci/if_bgereg.h sys/dev/pci/if_bgereg.h index a6846bc..852fffa 100644 --- sys/dev/pci/if_bgereg.h +++ sys/dev/pci/if_bgereg.h @@ -961,10 +961,11 @@ #define BGE_MIMODE_SHORTPREAMBLE 0x00000002 #define BGE_MIMODE_AUTOPOLL 0x00000010 #define BGE_MIMODE_CLKCNT 0x001F0000 #define BGE_MIMODE_500KHZ_CONST 0x00008000 #define BGE_MIMODE_BASE 0x000C0000 +#define BGE_MIMODE_PHYADDR(x) ((x & 0x1F) << 5) /* * Send data initiator control registers. */ #define BGE_SDI_MODE 0x0C00