aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/vr/if_vr.c
diff options
context:
space:
mode:
authorRui Paulo <rpaulo@FreeBSD.org>2012-05-12 14:37:25 +0000
committerRui Paulo <rpaulo@FreeBSD.org>2012-05-12 14:37:25 +0000
commit82f98de5fecab777df03efe1594d7402e2cffc4c (patch)
tree889be61a23bc06df3cddf407f17f63f97b7ea14c /sys/dev/vr/if_vr.c
parent711f661393c0f971d750a262d0548c9550f4a5bc (diff)
downloadsrc-82f98de5fecab777df03efe1594d7402e2cffc4c.tar.gz
src-82f98de5fecab777df03efe1594d7402e2cffc4c.zip
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
Notes
Notes: svn path=/head/; revision=235334
Diffstat (limited to 'sys/dev/vr/if_vr.c')
-rw-r--r--sys/dev/vr/if_vr.c43
1 files changed, 31 insertions, 12 deletions
diff --git a/sys/dev/vr/if_vr.c b/sys/dev/vr/if_vr.c
index 6d99216178a9..787dda5698f1 100644
--- a/sys/dev/vr/if_vr.c
+++ b/sys/dev/vr/if_vr.c
@@ -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);
}