if_arge has had a strange bug that only appears during high traffic

levels. TX would hang, RX wouldn't. A bit of digging showed the interface
send queue was full, but IFF_DRV_OACTIVE was clear and the hardware TX
queue was empty.

It turns out that there wasn't a check to drain the interface send
queue once hardware TX had completed, so if the interface send queue
had filled up in the meantime, subsequent packets would be dropped
by the higher layers and if_start (and thus arge_start()) would never
be called.

The fix is simple - call arge_start_locked() in the software interrupt
handler after the hardware TX queue has been handled or a TX underrun
occured. This way the interface send queue gets drained.
This commit is contained in:
Adrian Chadd 2011-04-05 06:46:07 +00:00
parent 85df7b525a
commit a043f08ec2
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=220357

View File

@ -1854,6 +1854,27 @@ arge_intr(void *arg)
}
}
/*
* If we've finished TXing and there's space for more packets
* to be queued for TX, do so. Otherwise we may end up in a
* situation where the interface send queue was filled
* whilst the hardware queue was full, then the hardware
* queue was drained by the interface send queue wasn't,
* and thus if_start() is never called to kick-start
* the send process (and all subsequent packets are simply
* discarded.
*
* XXX TODO: make sure that the hardware deals nicely
* with the possibility of the queue being enabled above
* after a TX underrun, then having the hardware queue added
* to below.
*/
if (status & (DMA_INTR_TX_PKT_SENT | DMA_INTR_TX_UNDERRUN) &&
(ifp->if_drv_flags & IFF_DRV_OACTIVE) == 0) {
if (!IFQ_IS_EMPTY(&ifp->if_snd))
arge_start_locked(ifp);
}
/*
* We handled all bits, clear status
*/