diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2014-07-03 13:26:06 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2014-07-03 13:26:06 +0000 |
commit | 586d750798150b1bd0db0465ddefe1305923ea91 (patch) | |
tree | 0a8d308e28077d7deb9521ef5fd072fb76262372 /sys/dev/pci/if_bge.c | |
parent | 5b60228aa8af4c04eb19307df7f3da685445cfac (diff) |
sending a heavily fragmented packet will cause the bus_dmamap_load
in bge_encap to fail because the dmamap lacks space, not necessarily
because the ring is full. however, bge_encap failure sets the OACTIVE
flag on the interface and keeps the packet at the start of the send
queue.
the next time we try to fill the tx ring we'll try to load the same
packet and fail. an empty tx ring means bge_txeof hasnt got anything
which is where the OACTIVE condition is cleared.
this diff adds handling of fragmented packets via m_defrag.
this might fix the issues landry@ has been complaining about on his
bulk build machines. i can reproduce the above problem in contrived
circumstances here and this diff fixes it, so its going in so landry@
is forced to test it.
Diffstat (limited to 'sys/dev/pci/if_bge.c')
-rw-r--r-- | sys/dev/pci/if_bge.c | 17 |
1 files changed, 14 insertions, 3 deletions
diff --git a/sys/dev/pci/if_bge.c b/sys/dev/pci/if_bge.c index e31ae3ee060..3666964ab8b 100644 --- a/sys/dev/pci/if_bge.c +++ b/sys/dev/pci/if_bge.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_bge.c,v 1.354 2014/04/22 11:54:46 naddy Exp $ */ +/* $OpenBSD: if_bge.c,v 1.355 2014/07/03 13:26:05 dlg Exp $ */ /* * Copyright (c) 2001 Wind River Systems @@ -4022,9 +4022,20 @@ doit: * the fragment pointers. Stop when we run out * of fragments or hit the end of the mbuf chain. */ - if (bus_dmamap_load_mbuf(sc->bge_dmatag, dmamap, m_head, - BUS_DMA_NOWAIT)) + switch (bus_dmamap_load_mbuf(sc->bge_dmatag, dmamap, m_head, + BUS_DMA_NOWAIT)) { + case 0: + break; + case EFBIG: + if (m_defrag(m_head, M_DONTWAIT) == 0 && + bus_dmamap_load_mbuf(sc->bge_dmatag, dmamap, m_head, + BUS_DMA_NOWAIT) == 0) + break; + + /* FALLTHROUGH */ + default: return (ENOBUFS); + } /* Check if we have enough free send BDs. */ if (sc->bge_txcnt + dmamap->dm_nsegs >= BGE_TX_RING_CNT) |