diff options
author | delphij <delphij@FreeBSD.org> | 2007-01-11 03:17:28 +0000 |
---|---|---|
committer | delphij <delphij@FreeBSD.org> | 2007-01-11 03:17:28 +0000 |
commit | 83499bc2d958aa69d2fa52ddaa4c7e8d3d04b929 (patch) | |
tree | fc680fb03443e0aa75145e4566ca1ba603eee513 /sys | |
parent | a379d6b5a481f8396d68e25339b4e8704740afdf (diff) | |
download | FreeBSD-src-83499bc2d958aa69d2fa52ddaa4c7e8d3d04b929.zip FreeBSD-src-83499bc2d958aa69d2fa52ddaa4c7e8d3d04b929.tar.gz |
- Instead of if_watchdog/if_timer interface use our own timer
that piggybacks on bce_tick() callout.
- Instead of unconditionally resetting the controller, try to
skip the reset in case we got a pause frame, like em(4) did.
- Lock bce_tick() using callout_init_mtx().
Discussed with/Reviewed by: glebius, scottl, davidch
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/bce/if_bce.c | 55 | ||||
-rw-r--r-- | sys/dev/bce/if_bcereg.h | 2 |
2 files changed, 28 insertions, 29 deletions
diff --git a/sys/dev/bce/if_bce.c b/sys/dev/bce/if_bce.c index 70cb64b..b091101 100644 --- a/sys/dev/bce/if_bce.c +++ b/sys/dev/bce/if_bce.c @@ -303,7 +303,7 @@ static int bce_tx_encap (struct bce_softc *, struct mbuf **); static void bce_start_locked (struct ifnet *); static void bce_start (struct ifnet *); static int bce_ioctl (struct ifnet *, u_long, caddr_t); -static void bce_watchdog (struct ifnet *); +static void bce_watchdog (struct bce_softc *); static int bce_ifmedia_upd (struct ifnet *); static void bce_ifmedia_sts (struct ifnet *, struct ifmediareq *); static void bce_init_locked (struct bce_softc *); @@ -326,7 +326,6 @@ static void bce_poll (struct ifnet *, enum poll_cmd, int); static void bce_intr (void *); static void bce_set_rx_mode (struct bce_softc *); static void bce_stats_update (struct bce_softc *); -static void bce_tick_locked (struct bce_softc *); static void bce_tick (void *); static void bce_add_sysctls (struct bce_softc *); @@ -721,8 +720,6 @@ bce_attach(device_t dev) ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; ifp->if_ioctl = bce_ioctl; ifp->if_start = bce_start; - ifp->if_timer = 0; - ifp->if_watchdog = bce_watchdog; ifp->if_init = bce_init; ifp->if_mtu = ETHERMTU; ifp->if_hwassist = BCE_IF_HWASSIST; @@ -766,7 +763,7 @@ bce_attach(device_t dev) #if __FreeBSD_version < 500000 callout_init(&sc->bce_stat_ch); #else - callout_init(&sc->bce_stat_ch, CALLOUT_MPSAFE); + callout_init_mtx(&sc->bce_stat_ch, &sc->bce_mtx, 0); #endif /* Hookup IRQ last. */ @@ -3123,7 +3120,7 @@ bce_stop(struct bce_softc *sc) } ifp->if_flags = itmp; - ifp->if_timer = 0; + sc->watchdog_timer = 0; sc->bce_link = 0; @@ -3889,7 +3886,7 @@ bce_phy_intr(struct bce_softc *sc) sc->bce_link = 0; callout_stop(&sc->bce_stat_ch); - bce_tick_locked(sc); + bce_tick(sc); /* Update the status_attn_bits_ack field in the status block. */ if (new_link_state) { @@ -4296,7 +4293,7 @@ bce_tx_intr(struct bce_softc *sc) } /* Clear the TX timeout timer. */ - ifp->if_timer = 0; + sc->watchdog_timer = 0; /* Clear the tx hardware queue full flag. */ if ((sc->used_tx_bd + BCE_TX_SLACK_SPACE) < USABLE_TX_BD) { @@ -4762,7 +4759,7 @@ bce_start_locked(struct ifnet *ifp) REG_WR(sc, MB_TX_CID_ADDR + BCE_L2CTX_TX_HOST_BSEQ, sc->tx_prod_bseq); /* Set the tx timeout. */ - ifp->if_timer = BCE_TX_TIMEOUT; + sc->watchdog_timer = BCE_TX_TIMEOUT; bce_start_locked_exit: return; @@ -4995,25 +4992,34 @@ bce_ioctl_exit: /* Nothing. */ /****************************************************************************/ static void -bce_watchdog(struct ifnet *ifp) +bce_watchdog(struct bce_softc *sc) { - struct bce_softc *sc = ifp->if_softc; DBRUN(BCE_WARN_SEND, bce_dump_driver_state(sc); bce_dump_status_block(sc)); + BCE_LOCK_ASSERT(sc); + + if (sc->watchdog_timer == 0 || --sc->watchdog_timer) + return; + + /* + * If we are in this routine because of pause frames, then + * don't reset the hardware. + */ + if (REG_RD(sc, BCE_EMAC_TX_STATUS) & BCE_EMAC_TX_STATUS_XOFFED) + return; + BCE_PRINTF(sc, "%s(%d): Watchdog timeout occurred, resetting!\n", __FILE__, __LINE__); /* DBRUN(BCE_FATAL, bce_breakpoint(sc)); */ - BCE_LOCK(sc); - ifp->if_drv_flags &= ~IFF_DRV_RUNNING; + sc->bce_ifp->if_drv_flags &= ~IFF_DRV_RUNNING; bce_init_locked(sc); - ifp->if_oerrors++; - BCE_UNLOCK(sc); + sc->bce_ifp->if_oerrors++; } @@ -5514,8 +5520,9 @@ bce_stats_update(struct bce_softc *sc) static void -bce_tick_locked(struct bce_softc *sc) +bce_tick(void *xsc) { + struct bce_softc *sc = xsc; struct mii_data *mii = NULL; struct ifnet *ifp; u32 msg; @@ -5535,6 +5542,9 @@ bce_tick_locked(struct bce_softc *sc) /* Update the statistics from the hardware statistics block. */ bce_stats_update(sc); + /* Check that chip hasn't hang. */ + bce_watchdog(sc); + /* Schedule the next tick. */ callout_reset( &sc->bce_stat_ch, /* callout */ @@ -5569,19 +5579,6 @@ bce_tick_locked_exit: } -static void -bce_tick(void *xsc) -{ - struct bce_softc *sc; - - sc = xsc; - - BCE_LOCK(sc); - bce_tick_locked(sc); - BCE_UNLOCK(sc); -} - - #ifdef BCE_DEBUG /****************************************************************************/ /* Allows the driver state to be dumped through the sysctl interface. */ diff --git a/sys/dev/bce/if_bcereg.h b/sys/dev/bce/if_bcereg.h index ec37324..e268dc8 100644 --- a/sys/dev/bce/if_bcereg.h +++ b/sys/dev/bce/if_bcereg.h @@ -4755,6 +4755,8 @@ struct bce_softc int bce_link; struct callout bce_stat_ch; + int watchdog_timer; /* ticks until chip reset */ + /* Frame size and mbuf allocation size for RX frames. */ u32 max_frame_size; int mbuf_alloc_size; |