Index: sys/dev/nfe/if_nfe.c =================================================================== --- sys/dev/nfe/if_nfe.c (revision 215194) +++ sys/dev/nfe/if_nfe.c (working copy) @@ -828,8 +828,14 @@ case IFM_100_TX: case IFM_1000_T: sc->nfe_link = 1; +#if 1 + printf("LINK UP\n"); +#endif break; default: +#if 1 + printf("LINK DOWN\n"); +#endif break; } } @@ -2270,6 +2276,8 @@ NFE_LOCK_ASSERT(sc); + if (sc->txq.queued == 0) + return; bus_dmamap_sync(sc->txq.tx_desc_tag, sc->txq.tx_desc_map, BUS_DMASYNC_POSTREAD); @@ -2566,6 +2574,14 @@ return; } + /* + * Because there is a possibility of losing TX completion + * interrupts, reclaim transmitted buffers here instead + * of relying on periodic firing of nfe_tick. + */ + if (sc->txq.queued > (NFE_TX_RING_COUNT * 2) / 3) + nfe_txeof(sc); + for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) { IFQ_DRV_DEQUEUE(&ifp->if_snd, m0); if (m0 == NULL) @@ -2607,15 +2623,6 @@ if (sc->nfe_watchdog_timer == 0 || --sc->nfe_watchdog_timer) return; - /* Check if we've lost Tx completion interrupt. */ - nfe_txeof(sc); - if (sc->txq.queued == 0) { - if_printf(ifp, "watchdog timeout (missed Tx interrupts) " - "-- recovering\n"); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - taskqueue_enqueue_fast(sc->nfe_tq, &sc->nfe_tx_task); - return; - } /* Check if we've lost start Tx command. */ sc->nfe_force_tx++; if (sc->nfe_force_tx <= 3) { @@ -2922,6 +2929,12 @@ mii = device_get_softc(sc->nfe_miibus); mii_tick(mii); nfe_stats_update(sc); + /* + * It seems some MCP controllers have a silicon bug that + * TX completion interrupts are not delivered under certain + * conditions so reclaim transmitted buffers here. + */ + nfe_txeof(sc); nfe_watchdog(ifp); callout_reset(&sc->nfe_stat_ch, hz, nfe_tick, sc); }