1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-23 11:18:54 +00:00

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
This commit is contained in:
Rui Paulo 2012-05-12 14:37:25 +00:00
parent 711f661393
commit 82f98de5fe
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=235334
2 changed files with 32 additions and 12 deletions

View File

@ -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,8 +1657,28 @@ 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;
@ -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);
}

View File

@ -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)