Fix one race and one fence post error. When the TX buffer was
completely full, we'd not complete any of the mbufs due to the fence post error (this creates a large leak). When this is fixed, we still leak, but at a much smaller rate due to a race between ateintr and atestart_locked as well as an asymmetry where atestart_locked is called from elsewhere. Ensure that we free in-flight packets that have completed there as well. Also remove needless check for NULL on mb, checked earlier in the loop and simplify a redundant if. MFC after: 3 days
This commit is contained in:
parent
e53c69c1f5
commit
19dab280cc
@ -947,10 +947,8 @@ ate_intr(void *xsc)
|
||||
|
||||
} while (!done);
|
||||
|
||||
if (mb != NULL) {
|
||||
ifp->if_ipackets++;
|
||||
(*ifp->if_input)(ifp, mb);
|
||||
}
|
||||
ifp->if_ipackets++;
|
||||
(*ifp->if_input)(ifp, mb);
|
||||
}
|
||||
}
|
||||
|
||||
@ -974,16 +972,14 @@ ate_intr(void *xsc)
|
||||
sc->tx_descs[sc->txtail + 1].status |= ETHB_TX_USED;
|
||||
}
|
||||
|
||||
while (sc->txtail != sc->txhead &&
|
||||
sc->tx_descs[sc->txtail].status & ETHB_TX_USED ) {
|
||||
|
||||
while ((sc->tx_descs[sc->txtail].status & ETHB_TX_USED) &&
|
||||
sc->sent_mbuf[sc->txtail] != NULL) {
|
||||
bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txtail],
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
bus_dmamap_unload(sc->mtag, sc->tx_map[sc->txtail]);
|
||||
m_freem(sc->sent_mbuf[sc->txtail]);
|
||||
sc->tx_descs[sc->txtail].addr = 0;
|
||||
sc->sent_mbuf[sc->txtail] = NULL;
|
||||
|
||||
ifp->if_opackets++;
|
||||
sc->txtail = NEXT_TX_IDX(sc, sc->txtail);
|
||||
}
|
||||
@ -1118,12 +1114,10 @@ atestart_locked(struct ifnet *ifp)
|
||||
* xmit packets. We use OACTIVE to indicate "we can stuff more
|
||||
* into our buffers (clear) or not (set)."
|
||||
*/
|
||||
if (!sc->is_emacb) {
|
||||
/* RM9200 has only two hardware entries */
|
||||
if (!sc->is_emacb && (RD4(sc, ETH_TSR) & ETH_TSR_BNQ) == 0) {
|
||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
||||
return;
|
||||
}
|
||||
/* RM9200 has only two hardware entries */
|
||||
if (!sc->is_emacb && (RD4(sc, ETH_TSR) & ETH_TSR_BNQ) == 0) {
|
||||
ifp->if_drv_flags |= IFF_DRV_OACTIVE;
|
||||
return;
|
||||
}
|
||||
|
||||
IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
|
||||
@ -1146,6 +1140,21 @@ atestart_locked(struct ifnet *ifp)
|
||||
m_freem(m);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* There's a small race between the loop in ate_intr finishing
|
||||
* and the check above to see if the packet was finished, as well
|
||||
* as when atestart gets called via other paths. Loose the race
|
||||
* gracefully and free the mbuf...
|
||||
*/
|
||||
if (sc->sent_mbuf[sc->txhead] != NULL) {
|
||||
bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txtail],
|
||||
BUS_DMASYNC_POSTWRITE);
|
||||
bus_dmamap_unload(sc->mtag, sc->tx_map[sc->txtail]);
|
||||
m_free(sc->sent_mbuf[sc->txhead]);
|
||||
ifp->if_opackets++;
|
||||
}
|
||||
|
||||
sc->sent_mbuf[sc->txhead] = m;
|
||||
|
||||
bus_dmamap_sync(sc->mtag, sc->tx_map[sc->txhead],
|
||||
|
Loading…
x
Reference in New Issue
Block a user