Index: if_bge.c =================================================================== RCS file: /home/ncvs/src/sys/dev/bge/if_bge.c,v retrieving revision 1.91.2.18.2.1 diff -u -r1.91.2.18.2.1 if_bge.c --- if_bge.c 21 Dec 2006 21:53:54 -0000 1.91.2.18.2.1 +++ if_bge.c 5 Jan 2007 21:38:40 -0000 @@ -312,7 +312,6 @@ static void bge_txeof(struct bge_softc *); static void bge_rxeof(struct bge_softc *); -static void bge_tick_locked(struct bge_softc *); static void bge_tick(void *); static void bge_stats_update(struct bge_softc *); static void bge_stats_update_regs(struct bge_softc *); @@ -325,7 +324,7 @@ static void bge_init_locked(struct bge_softc *); static void bge_init(void *); static void bge_stop(struct bge_softc *); -static void bge_watchdog(struct ifnet *); +static void bge_watchdog(struct bge_softc *); static void bge_shutdown(device_t); static int bge_ifmedia_upd_locked(struct ifnet *); static int bge_ifmedia_upd(struct ifnet *); @@ -1348,8 +1347,8 @@ CSR_WRITE_4(sc, BGE_HCC_RX_COAL_TICKS_INT, 0); CSR_WRITE_4(sc, BGE_HCC_TX_COAL_TICKS_INT, 0); } - CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 0); - CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 0); + CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 1); + CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 1); /* Set up address of statistics block */ if (!(BGE_IS_5705_OR_BEYOND(sc))) { @@ -1688,7 +1687,7 @@ * Allocate the parent bus DMA tag appropriate for PCI. */ error = bus_dma_tag_create(NULL, /* parent */ - PAGE_SIZE, 0, /* alignment, boundary */ + 1, 0, /* alignment, boundary */ BUS_SPACE_MAXADDR, /* lowaddr */ BUS_SPACE_MAXADDR, /* highaddr */ NULL, NULL, /* filter, filterarg */ @@ -2107,7 +2106,6 @@ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = bge_ioctl; ifp->if_start = bge_start; - ifp->if_watchdog = bge_watchdog; ifp->if_init = bge_init; ifp->if_mtu = ETHERMTU; ifp->if_snd.ifq_drv_maxlen = BGE_TX_RING_CNT - 1; @@ -2197,7 +2195,7 @@ * Call MI attach routine. */ ether_ifattach(ifp, eaddr); - callout_init(&sc->bge_stat_ch, CALLOUT_MPSAFE); + callout_init_mtx(&sc->bge_stat_ch, &sc->bge_mtx, 0); /* * Hookup IRQ last. @@ -2233,6 +2231,8 @@ bge_reset(sc); BGE_UNLOCK(sc); + callout_drain(&sc->bge_stat_ch); + ether_ifdetach(ifp); if (sc->bge_tbi) { @@ -2614,11 +2614,12 @@ } sc->bge_txcnt--; BGE_INC(sc->bge_tx_saved_considx, BGE_TX_RING_CNT); - ifp->if_timer = 0; } if (cur_tx != NULL) ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; + if (sc->bge_txcnt == 0) + sc->bge_timer = 0; } #ifdef DEVICE_POLLING @@ -2684,13 +2685,32 @@ #endif /* + * Ack the interrupt by writing something to BGE_MBX_IRQ0_LO. Don't + * disable interrupts by writing nonzero like we used to, since with + * our current organization this just gives complications and + * pessimizations for re-enabling interrupts. We used to have races + * instead of the necessary complications. Disabling interrupts + * would just reduce the chance of a status update while we are + * running (by switching to the interrupt-mode coalescence + * parameters), but this chance is already very low so it is more + * efficient to get another interrupt than prevent it. + * + * We do the ack first to ensure another interrupt if there is a + * status update after the ack. We don't check for the status + * changing later because it is more efficient to get another + * interrupt than prevent it, not quite as above (not checking is + * a smaller optimization than not toggling the interrupt enable, + * since checking doesn't involve PCI accesses and toggling require + * the status check). So toggling would probably be a pessimization + * even with MSI. It would only be needed for using a task queue. + */ + CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0); + + /* * Do the mandatory PCI flush as well as get the link status. */ statusword = CSR_READ_4(sc, BGE_MAC_STS) & BGE_MACSTAT_LINK_CHANGED; - /* Ack interrupt and stop others from occuring. */ - CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1); - /* Make sure the descriptor ring indexes are coherent. */ bus_dmamap_sync(sc->bge_cdata.bge_status_tag, sc->bge_cdata.bge_status_map, BUS_DMASYNC_POSTREAD); @@ -2710,9 +2730,6 @@ bge_txeof(sc); } - /* Re-enable interrupts. */ - CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0); - if (ifp->if_drv_flags & IFF_DRV_RUNNING && !IFQ_DRV_IS_EMPTY(&ifp->if_snd)) bge_start_locked(ifp); @@ -2721,12 +2738,18 @@ } static void -bge_tick_locked(struct bge_softc *sc) +bge_tick(void *xsc) { + struct bge_softc *sc = xsc; struct mii_data *mii = NULL; BGE_LOCK_ASSERT(sc); + /* Synchronize with possible callout reset/stop. */ + if (callout_pending(&sc->bge_stat_ch) || + !callout_active(&sc->bge_stat_ch)) + return; + if (BGE_IS_5705_OR_BEYOND(sc)) bge_stats_update_regs(sc); else @@ -2751,45 +2774,22 @@ } } - callout_reset(&sc->bge_stat_ch, hz, bge_tick, sc); -} - -static void -bge_tick(void *xsc) -{ - struct bge_softc *sc; - - sc = xsc; + bge_watchdog(sc); - BGE_LOCK(sc); - bge_tick_locked(sc); - BGE_UNLOCK(sc); + callout_reset(&sc->bge_stat_ch, hz, bge_tick, sc); } static void bge_stats_update_regs(struct bge_softc *sc) { - struct bge_mac_stats_regs stats; struct ifnet *ifp; - uint32_t *s; - u_long cnt; /* current register value */ - int i; ifp = sc->bge_ifp; - s = (uint32_t *)&stats; - for (i = 0; i < sizeof(struct bge_mac_stats_regs); i += 4) { - *s = CSR_READ_4(sc, BGE_RX_STATS + i); - s++; - } + ifp->if_collisions += CSR_READ_4(sc, BGE_MAC_STATS + + offsetof(struct bge_mac_stats_regs, etherStatsCollisions)); - cnt = stats.dot3StatsSingleCollisionFrames + - stats.dot3StatsMultipleCollisionFrames + - stats.dot3StatsExcessiveCollisions + - stats.dot3StatsLateCollisions; - ifp->if_collisions += cnt >= sc->bge_tx_collisions ? - cnt - sc->bge_tx_collisions : cnt; - sc->bge_tx_collisions = cnt; + ifp->if_ierrors += CSR_READ_4(sc, BGE_RXLP_LOCSTAT_IFIN_DROPS); } static void @@ -2797,7 +2797,7 @@ { struct ifnet *ifp; bus_size_t stats; - u_long cnt; /* current register value */ + uint32_t cnt; /* current register value */ ifp = sc->bge_ifp; @@ -2814,18 +2814,15 @@ txstats.dot3StatsExcessiveCollisions.bge_addr_lo); cnt += READ_STAT(sc, stats, txstats.dot3StatsLateCollisions.bge_addr_lo); - ifp->if_collisions += cnt >= sc->bge_tx_collisions ? - cnt - sc->bge_tx_collisions : cnt; + ifp->if_collisions += (uint32_t)(cnt - sc->bge_tx_collisions); sc->bge_tx_collisions = cnt; cnt = READ_STAT(sc, stats, ifInDiscards.bge_addr_lo); - ifp->if_ierrors += cnt >= sc->bge_rx_discards ? - cnt - sc->bge_rx_discards : cnt; + ifp->if_ierrors += (uint32_t)(cnt - sc->bge_rx_discards); sc->bge_rx_discards = cnt; cnt = READ_STAT(sc, stats, txstats.ifOutDiscards.bge_addr_lo); - ifp->if_oerrors += cnt >= sc->bge_tx_discards ? - cnt - sc->bge_tx_discards : cnt; + ifp->if_oerrors += (uint32_t)(cnt - sc->bge_tx_discards); sc->bge_tx_discards = cnt; #undef READ_STAT @@ -3055,7 +3052,7 @@ /* * Set a timeout in case the chip goes out to lunch. */ - ifp->if_timer = 5; + sc->bge_timer = 5; } /* @@ -3149,6 +3146,9 @@ /* Init our RX return ring index. */ sc->bge_rx_saved_considx = 0; + /* Init our RX/TX stat counters. */ + sc->bge_rx_discards = sc->bge_tx_discards = sc->bge_tx_collisions = 0; + /* Init TX ring. */ bge_init_tx_ring(sc); @@ -3167,8 +3167,6 @@ BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR); CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1); - CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 1); - CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 1); } else #endif @@ -3405,16 +3403,12 @@ BGE_SETBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR); CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 1); - CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 1); - CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 1); ifp->if_capenable |= IFCAP_POLLING; BGE_UNLOCK(sc); } else { error = ether_poll_deregister(ifp); /* Enable interrupt even in error case */ BGE_LOCK(sc); - CSR_WRITE_4(sc, BGE_HCC_RX_MAX_COAL_BDS_INT, 0); - CSR_WRITE_4(sc, BGE_HCC_TX_MAX_COAL_BDS_INT, 0); BGE_CLRBIT(sc, BGE_PCI_MISC_CTL, BGE_PCIMISCCTL_MASK_PCI_INTR); CSR_WRITE_4(sc, BGE_MBX_IRQ0_LO, 0); @@ -3441,16 +3435,21 @@ } static void -bge_watchdog(struct ifnet *ifp) +bge_watchdog(struct bge_softc *sc) { - struct bge_softc *sc; + struct ifnet *ifp; - sc = ifp->if_softc; + BGE_LOCK_ASSERT(sc); + + if (sc->bge_timer == 0 || --sc->bge_timer) + return; + + ifp = sc->bge_ifp; if_printf(ifp, "watchdog timeout -- resetting\n"); ifp->if_drv_flags &= ~IFF_DRV_RUNNING; - bge_init(sc); + bge_init_locked(sc); ifp->if_oerrors++; } @@ -3557,12 +3556,7 @@ sc->bge_tx_saved_considx = BGE_TXCONS_UNSET; - /* - * We can't just call bge_link_upd() cause chip is almost stopped so - * bge_link_upd -> bge_tick_locked -> bge_stats_update sequence may - * lead to hardware deadlock. So we just clearing MAC's link state - * (PHY may still have link UP). - */ + /* Clear MAC's link state (PHY may still have link UP). */ if (bootverbose && sc->bge_link) if_printf(sc->bge_ifp, "link DOWN\n"); sc->bge_link = 0; @@ -3649,10 +3643,8 @@ sc->bge_chipid != BGE_CHIPID_BCM5700_B2) { status = CSR_READ_4(sc, BGE_MAC_STS); if (status & BGE_MACSTAT_MI_INTERRUPT) { - callout_stop(&sc->bge_stat_ch); - bge_tick_locked(sc); - mii = device_get_softc(sc->bge_miibus); + mii_pollstat(mii); if (!sc->bge_link && mii->mii_media_status & IFM_ACTIVE && IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { @@ -3708,10 +3700,8 @@ if (link != sc->bge_link || sc->bge_asicrev == BGE_ASICREV_BCM5700) { - callout_stop(&sc->bge_stat_ch); - bge_tick_locked(sc); - mii = device_get_softc(sc->bge_miibus); + mii_pollstat(mii); if (!sc->bge_link && mii->mii_media_status & IFM_ACTIVE && IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) { Index: if_bgereg.h =================================================================== RCS file: /home/ncvs/src/sys/dev/bge/if_bgereg.h,v retrieving revision 1.36.2.8.2.1 diff -u -r1.36.2.8.2.1 if_bgereg.h --- if_bgereg.h 21 Dec 2006 21:53:54 -0000 1.36.2.8.2.1 +++ if_bgereg.h 5 Jan 2007 21:33:22 -0000 @@ -266,6 +266,15 @@ #define BGE_CHIPID_BCM5714_B3 0x80030000 #define BGE_CHIPID_BCM5715_A0 0x90000000 #define BGE_CHIPID_BCM5715_A1 0x90010000 +#define BGE_CHIPID_BCM5755_A0 0xa0000000 +#define BGE_CHIPID_BCM5755_A1 0xa0010000 +#define BGE_CHIPID_BCM5755_A2 0xa0020000 +#define BGE_CHIPID_BCM5754_A0 0xb0000000 +#define BGE_CHIPID_BCM5754_A1 0xb0010000 +#define BGE_CHIPID_BCM5754_A2 0xb0020000 +#define BGE_CHIPID_BCM5787_A0 0xb0000000 +#define BGE_CHIPID_BCM5787_A1 0xb0010000 +#define BGE_CHIPID_BCM5787_A2 0xb0020000 /* shorthand one */ #define BGE_ASICREV(x) ((x) >> 28) @@ -567,8 +576,7 @@ #define BGE_SERDES_STS 0x0594 #define BGE_SGDIG_CFG 0x05B0 #define BGE_SGDIG_STS 0x05B4 -#define BGE_RX_STATS 0x0800 -#define BGE_TX_STATS 0x0880 +#define BGE_MAC_STATS 0x0800 /* Ethernet MAC Mode register */ #define BGE_MACMODE_RESET 0x00000001 @@ -1654,6 +1662,7 @@ #define BGE_EE_CTL 0x6840 #define BGE_MDI_CTL 0x6844 #define BGE_EE_DELAY 0x6848 +#define BGE_FASTBOOT_PC 0x6894 /* Mode control register */ #define BGE_MODECTL_INT_SNDCOAL_ONLY 0x00000001 @@ -2462,12 +2471,13 @@ int bge_txcnt; int bge_link; /* link state */ int bge_link_evt; /* pending link event */ + int bge_timer; struct callout bge_stat_ch; char *bge_vpd_prodname; char *bge_vpd_readonly; - u_long bge_rx_discards; - u_long bge_tx_discards; - u_long bge_tx_collisions; + uint32_t bge_rx_discards; + uint32_t bge_tx_discards; + uint32_t bge_tx_collisions; #ifdef DEVICE_POLLING int rxcycles; #endif /* DEVICE_POLLING */