summaryrefslogtreecommitdiffstats
path: root/sys/dev/em
diff options
context:
space:
mode:
authorandre <andre@FreeBSD.org>2006-09-29 13:12:38 +0000
committerandre <andre@FreeBSD.org>2006-09-29 13:12:38 +0000
commitd066071e5efd02a0f61eba87a164fdc18b623b00 (patch)
treef6fe2edf88ae4bbda04cc10d81a615205d4e1da2 /sys/dev/em
parent8405ff182feb5e479edb4b36b3345b5e9c1c0d84 (diff)
downloadFreeBSD-src-d066071e5efd02a0f61eba87a164fdc18b623b00.zip
FreeBSD-src-d066071e5efd02a0f61eba87a164fdc18b623b00.tar.gz
Handle all error cases from bus_dmamap_load_mbuf_sg(). Those are:
- EFBIG means the mbuf chain was too long and bus_dma ran out of segments. Defragment the mbuf chain and try again. (Already existed, not changed.) - ENOMEM means bus_dma could not obtain enough bounce buffers at this point in time. Defer sending and try again later. - All other errors, in particular EINVAL, are fatal and prevent the mbuf chain from ever going through. Drop it and report error. - Checking (nsegs == 0) is unnecessary as bus_dmamap_load_mbuf_sg() always reports an error if it is < 1. This prevents broken packets from clogging the interface queue indefinately. Discussed with: scottl Reviewed by: jfv
Diffstat (limited to 'sys/dev/em')
-rw-r--r--sys/dev/em/if_em.c26
1 files changed, 21 insertions, 5 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index ffc4988..112f796 100644
--- a/sys/dev/em/if_em.c
+++ b/sys/dev/em/if_em.c
@@ -1526,8 +1526,19 @@ em_encap(struct adapter *adapter, struct mbuf **m_headp)
tx_buffer = &adapter->tx_buffer_area[adapter->next_avail_tx_desc];
tx_buffer_last = tx_buffer;
map = tx_buffer->map;
+
error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, *m_headp, segs,
&nsegs, BUS_DMA_NOWAIT);
+
+ /*
+ * There are two types of errors we can (try) to handle:
+ * - EFBIG means the mbuf chain was too long and bus_dma ran
+ * out of segments. Defragment the mbuf chain and try again.
+ * - ENOMEM means bus_dma could not obtain enough bounce buffers
+ * at this point in time. Defer sending and try again later.
+ * All other errors, in particular EINVAL, are fatal and prevent the
+ * mbuf chain from ever going through. Drop it and report error.
+ */
if (error == EFBIG) {
struct mbuf *m;
@@ -1540,22 +1551,27 @@ em_encap(struct adapter *adapter, struct mbuf **m_headp)
return (ENOBUFS);
}
*m_headp = m;
+
error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, *m_headp,
segs, &nsegs, BUS_DMA_NOWAIT);
- if (error != 0) {
+
+ if (error == ENOMEM) {
+ adapter->no_tx_dma_setup++;
+ return (error);
+ } else if (error != 0) {
adapter->no_tx_dma_setup++;
m_freem(*m_headp);
*m_headp = NULL;
return (error);
}
- } else if (error != 0) {
+ } else if (error == ENOMEM) {
adapter->no_tx_dma_setup++;
return (error);
- }
- if (nsegs == 0) {
+ } else if (error != 0) {
+ adapter->no_tx_dma_setup++;
m_freem(*m_headp);
*m_headp = NULL;
- return (EIO);
+ return (error);
}
/*
OpenPOWER on IntegriCloud