diff options
-rw-r--r-- | sys/arm/ti/cpsw/if_cpsw.c | 43 | ||||
-rw-r--r-- | sys/arm/ti/cpsw/if_cpswvar.h | 4 |
2 files changed, 23 insertions, 24 deletions
diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c index 80cbe73..d08bf28 100644 --- a/sys/arm/ti/cpsw/if_cpsw.c +++ b/sys/arm/ti/cpsw/if_cpsw.c @@ -98,7 +98,7 @@ static int cpsw_ioctl(struct ifnet *ifp, u_long command, caddr_t data); static int cpsw_init_slot_lists(struct cpsw_softc *sc); static void cpsw_free_slot(struct cpsw_softc *sc, struct cpsw_slot *slot); static void cpsw_fill_rx_queue_locked(struct cpsw_softc *sc); -static void cpsw_watchdog(struct cpsw_softc *sc); +static void cpsw_tx_watchdog(struct cpsw_softc *sc); static void cpsw_intr_rx_thresh(void *arg); static void cpsw_intr_rx(void *arg); @@ -737,13 +737,7 @@ cpsw_start_locked(struct ifnet *ifp) cpsw_cpdma_write_txbd_next(prev_slot->index, cpsw_cpdma_txbd_paddr(first_new_slot->index)); } - /* If tx_retires hasn't changed, then we may have - lost a TX interrupt, so let the timer tick. */ sc->tx_enqueues += enqueued; - if (sc->tx_retires_at_wd_reset != sc->tx_retires) { - sc->tx_retires_at_wd_reset = sc->tx_retires; - sc->wd_timer = 5; - } sc->tx_queued += enqueued; if (sc->tx_queued > sc->tx_max_queued) { sc->tx_max_queued = sc->tx_queued; @@ -771,7 +765,6 @@ cpsw_stop_locked(struct cpsw_softc *sc) /* Stop tick engine */ callout_stop(&sc->wd_callout); - sc->wd_timer = 0; /* Wait for hardware to clear pending ops. */ CPSW_GLOBAL_UNLOCK(sc); @@ -1185,7 +1178,6 @@ cpsw_intr_tx_locked(void *arg) } sc->tx_retires += retires; sc->tx_queued -= retires; - sc->wd_timer = 0; } } @@ -1206,7 +1198,7 @@ cpsw_tick(void *msc) struct cpsw_softc *sc = msc; /* Check for TX timeout */ - cpsw_watchdog(sc); + cpsw_tx_watchdog(sc); mii_tick(sc->mii); @@ -1222,21 +1214,28 @@ cpsw_tick(void *msc) } static void -cpsw_watchdog(struct cpsw_softc *sc) +cpsw_tx_watchdog(struct cpsw_softc *sc) { - struct ifnet *ifp; + struct ifnet *ifp = sc->ifp; - ifp = sc->ifp; CPSW_GLOBAL_LOCK(sc); - if (sc->wd_timer == 0 || --sc->wd_timer) { - CPSW_GLOBAL_UNLOCK(sc); - return; + if (sc->tx_retires > sc->tx_retires_at_last_tick) { + sc->tx_wd_timer = 0; /* Stuff got sent. */ + } else if (sc->tx_queued == 0) { + sc->tx_wd_timer = 0; /* Nothing to send. */ + } else { + /* There was something to send but we didn't. */ + ++sc->tx_wd_timer; + if (sc->tx_wd_timer > 3) { + sc->tx_wd_timer = 0; + ifp->if_oerrors++; + if_printf(ifp, "watchdog timeout\n"); + cpsw_stop_locked(sc); + cpsw_init_locked(sc); + CPSW_DEBUGF(("watchdog reset completed\n")); + } } - - ifp->if_oerrors++; - if_printf(ifp, "watchdog timeout\n"); - cpsw_stop_locked(sc); - cpsw_init_locked(sc); + sc->tx_retires_at_last_tick = sc->tx_retires; CPSW_GLOBAL_UNLOCK(sc); } @@ -1381,7 +1380,7 @@ cpsw_init_locked(void *arg) /* Activate network interface */ sc->rx_running = 1; sc->tx_running = 1; - sc->wd_timer = 0; + sc->tx_wd_timer = 0; callout_reset(&sc->wd_callout, hz, cpsw_tick, sc); sc->ifp->if_drv_flags |= IFF_DRV_RUNNING; sc->ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; diff --git a/sys/arm/ti/cpsw/if_cpswvar.h b/sys/arm/ti/cpsw/if_cpswvar.h index 3cae489..35024c6 100644 --- a/sys/arm/ti/cpsw/if_cpswvar.h +++ b/sys/arm/ti/cpsw/if_cpswvar.h @@ -63,7 +63,7 @@ struct cpsw_softc { int cpsw_media_status; struct callout wd_callout; - int wd_timer; + int tx_wd_timer; bus_dma_tag_t mbuf_dtag; @@ -82,7 +82,7 @@ struct cpsw_softc { /* Statistics */ uint32_t tx_enqueues; /* total TX bufs added to queue */ uint32_t tx_retires; /* total TX bufs removed from queue */ - uint32_t tx_retires_at_wd_reset; /* used for watchdog */ + uint32_t tx_retires_at_last_tick; /* used for watchdog */ /* Note: tx_queued != tx_enqueues - tx_retires At driver reset, packets can be discarded from TX queue without being retired. */ |