Author: rpaulo Date: Sat May 12 14:37:25 2012 New Revision: 235334 URL: http://svn.freebsd.org/changeset/base/235334
Log: Convert the if_vr(4) driver model to the interrupt filter model and use a taskqueue. This gives a 16% performance improvement under high load on slow systems, especially when vr shares an interrupt with another device, which is common with the Alix x86 boards. Contrary to the other devices, I left the interrupt processing for loop in because there was no significant difference in performance and this should avoid enqueuing more taskqueues unnecessarily. We also decided to move the vr_start_locked() call inside the for loop because we found out that it helps performance since TCP ACKs now have a chance to go out quicker. Reviewed by: yongari (older version, same idea) Discussed with: yongari, jhb Modified: head/sys/dev/vr/if_vr.c head/sys/dev/vr/if_vrreg.h Modified: head/sys/dev/vr/if_vr.c ============================================================================== --- head/sys/dev/vr/if_vr.c Sat May 12 13:55:36 2012 (r235333) +++ head/sys/dev/vr/if_vr.c Sat May 12 14:37:25 2012 (r235334) @@ -165,7 +165,8 @@ static void vr_txeof(struct vr_softc *); static void vr_tick(void *); static int vr_error(struct vr_softc *, uint16_t); static void vr_tx_underrun(struct vr_softc *); -static void vr_intr(void *); +static int vr_intr(void *); +static void vr_int_task(void *, int); static void vr_start(struct ifnet *); static void vr_start_locked(struct ifnet *); static int vr_encap(struct vr_softc *, struct mbuf **); @@ -658,6 +659,8 @@ vr_attach(device_t dev) ifp->if_snd.ifq_maxlen = VR_TX_RING_CNT - 1; IFQ_SET_READY(&ifp->if_snd); + TASK_INIT(&sc->vr_inttask, 0, vr_int_task, sc); + /* Configure Tx FIFO threshold. */ sc->vr_txthresh = VR_TXTHRESH_MIN; if (sc->vr_revid < REV_ID_VT6105_A0) { @@ -784,7 +787,7 @@ vr_attach(device_t dev) /* Hook interrupt last to avoid having to lock softc. */ error = bus_setup_intr(dev, sc->vr_irq, INTR_TYPE_NET | INTR_MPSAFE, - NULL, vr_intr, sc, &sc->vr_intrhand); + vr_intr, NULL, sc, &sc->vr_intrhand); if (error) { device_printf(dev, "couldn't set up irq\n"); @@ -826,6 +829,7 @@ vr_detach(device_t dev) vr_stop(sc); VR_UNLOCK(sc); callout_drain(&sc->vr_stat_callout); + taskqueue_drain(taskqueue_fast, &sc->vr_inttask); ether_ifdetach(ifp); } if (sc->vr_miibus) @@ -1653,10 +1657,30 @@ vr_tx_underrun(struct vr_softc *sc) vr_tx_start(sc); } -static void +static int vr_intr(void *arg) { struct vr_softc *sc; + uint16_t status; + + sc = (struct vr_softc *)arg; + + status = CSR_READ_2(sc, VR_ISR); + if (status == 0 || status == 0xffff || (status & VR_INTRS) == 0) + return (FILTER_STRAY); + + /* Disable interrupts. */ + CSR_WRITE_2(sc, VR_IMR, 0x0000); + + taskqueue_enqueue_fast(taskqueue_fast, &sc->vr_inttask); + + return (FILTER_HANDLED); +} + +static void +vr_int_task(void *arg, int npending) +{ + struct vr_softc *sc; struct ifnet *ifp; uint16_t status; @@ -1668,9 +1692,6 @@ vr_intr(void *arg) goto done_locked; status = CSR_READ_2(sc, VR_ISR); - if (status == 0 || status == 0xffff || (status & VR_INTRS) == 0) - goto done_locked; - ifp = sc->vr_ifp; #ifdef DEVICE_POLLING if ((ifp->if_capenable & IFCAP_POLLING) != 0) @@ -1685,9 +1706,6 @@ vr_intr(void *arg) goto done_locked; } - /* Disable interrupts. */ - CSR_WRITE_2(sc, VR_IMR, 0x0000); - for (; (status & VR_INTRS) != 0;) { CSR_WRITE_2(sc, VR_ISR, status); if ((status & (VR_ISR_BUSERR | VR_ISR_LINKSTAT2 | @@ -1707,15 +1725,16 @@ vr_intr(void *arg) vr_rx_start(sc); } vr_txeof(sc); + + if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) + vr_start_locked(ifp); + status = CSR_READ_2(sc, VR_ISR); } /* Re-enable interrupts. */ CSR_WRITE_2(sc, VR_IMR, VR_INTRS); - if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd)) - vr_start_locked(ifp); - done_locked: VR_UNLOCK(sc); } Modified: head/sys/dev/vr/if_vrreg.h ============================================================================== --- head/sys/dev/vr/if_vrreg.h Sat May 12 13:55:36 2012 (r235333) +++ head/sys/dev/vr/if_vrreg.h Sat May 12 14:37:25 2012 (r235334) @@ -738,6 +738,7 @@ struct vr_softc { #ifdef DEVICE_POLLING int rxcycles; #endif + struct task vr_inttask; }; #define VR_LOCK(_sc) mtx_lock(&(_sc)->vr_mtx) _______________________________________________ svn-src-head@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"