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

Reply via email to