DF-3761 / fix.diff
--- a/sys/dev/netif/alc/if_alc.c +++ b/sys/dev/netif/alc/if_alc.c @@ -3224,7 +3224,7 @@ struct ifnet *ifp; struct rx_rdesc *rrd; uint32_t nsegs, status; - int rr_cons, prog; + int n, rr_cons, prog; bus_dmamap_sync(sc->alc_cdata.alc_rr_ring_tag, sc->alc_cdata.alc_rr_ring_map, @@ -3233,7 +3233,18 @@ sc->alc_cdata.alc_rx_ring_map, BUS_DMASYNC_POSTWRITE); rr_cons = sc->alc_cdata.alc_rr_cons; ifp = sc->alc_ifp; + /* + * Bound the number of Rx events serviced per interrupt with + * the (already existing but never used) process_limit knob. + * Without it a line-rate flood keeps the return ring + * perpetually non-empty and this loop never terminates while + * the interrupt handler holds the serializer: NIC + one CPU + * livelock (FreeBSD bounds this loop the same way). + */ + n = sc->alc_process_limit; for (prog = 0; (ifp->if_flags & IFF_RUNNING) != 0;) { + if (n-- <= 0) + break; rrd = &sc->alc_rdata.alc_rr_ring[rr_cons]; status = le32toh(rrd->status); if ((status & RRD_VALID) == 0) |