aboutsummaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorEmmanuel Vadot <manu@FreeBSD.org>2017-11-18 21:12:06 +0000
committerEmmanuel Vadot <manu@FreeBSD.org>2017-11-18 21:12:06 +0000
commit3f9ade0643fa201b60cb48a339b62ef0f6bae90d (patch)
tree1a65055c7dc4ac83f3a3135170c106f6f2eadb7a /sys
parentbd9063297c518e5a9743cfe2d7df516d6c8054d9 (diff)
downloadsrc-3f9ade0643fa201b60cb48a339b62ef0f6bae90d.tar.gz
src-3f9ade0643fa201b60cb48a339b62ef0f6bae90d.zip
if_awg: drain tx buffers and clear rx buffers when stopping
Stale packets should not be transmitted when the interface comes up after being down. Count the successfully transmitted ones for statistics and drop the rest. Submitted by: Guy Yur <guyyur@gmail.com> Differential Revision: https://reviews.freebsd.org/D12539
Notes
Notes: svn path=/head/; revision=325985
Diffstat (limited to 'sys')
-rw-r--r--sys/arm/allwinner/if_awg.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/sys/arm/allwinner/if_awg.c b/sys/arm/allwinner/if_awg.c
index 64085703583a..81aca029082f 100644
--- a/sys/arm/allwinner/if_awg.c
+++ b/sys/arm/allwinner/if_awg.c
@@ -215,6 +215,8 @@ static struct resource_spec awg_spec[] = {
{ -1, 0 }
};
+static void awg_txeof(struct awg_softc *sc);
+
static int
awg_miibus_readreg(device_t dev, int phy, int reg)
{
@@ -809,6 +811,7 @@ awg_stop(struct awg_softc *sc)
{
if_t ifp;
uint32_t val;
+ int i;
AWG_ASSERT_LOCKED(sc);
@@ -843,6 +846,39 @@ awg_stop(struct awg_softc *sc)
sc->link = 0;
+ /* Finish handling transmitted buffers */
+ awg_txeof(sc);
+
+ /* Release any untransmitted buffers. */
+ for (i = sc->tx.next; sc->tx.queued > 0; i = TX_NEXT(i)) {
+ val = le32toh(sc->tx.desc_ring[i].status);
+ if ((val & TX_DESC_CTL) != 0)
+ break;
+ awg_clean_txbuf(sc, i);
+ }
+ sc->tx.next = i;
+ for (; sc->tx.queued > 0; i = TX_NEXT(i)) {
+ sc->tx.desc_ring[i].status = 0;
+ awg_clean_txbuf(sc, i);
+ }
+ sc->tx.cur = sc->tx.next;
+ bus_dmamap_sync(sc->tx.desc_tag, sc->tx.desc_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ /* Setup RX buffers for reuse */
+ bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ for (i = sc->rx.cur; ; i = RX_NEXT(i)) {
+ val = le32toh(sc->rx.desc_ring[i].status);
+ if ((val & RX_DESC_CTL) != 0)
+ break;
+ awg_reuse_rxdesc(sc, i);
+ }
+ sc->rx.cur = i;
+ bus_dmamap_sync(sc->rx.desc_tag, sc->rx.desc_map,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
if_setdrvflagbits(ifp, 0, IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
}