summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authoryongari <yongari@FreeBSD.org>2006-08-14 02:21:26 +0000
committeryongari <yongari@FreeBSD.org>2006-08-14 02:21:26 +0000
commit297f53342b73885fd27db30f6852e67f9a6c293a (patch)
treeaec9cb413c3563c1678700a91843eb8be6957a92 /sys
parent494fd63ce267ca352d6bf5af3a85075eecd61d76 (diff)
downloadFreeBSD-src-297f53342b73885fd27db30f6852e67f9a6c293a.zip
FreeBSD-src-297f53342b73885fd27db30f6852e67f9a6c293a.tar.gz
Make em(4) handle too many fragmented frame with m_defrag(9).
Previously em(4) requeued the failed mbuf chains from bus_dmamap_load_mbuf_sg(9) failure to resend it later. However, bus_dmamap_load_mbuf_sg(9) may never complete its request as the fragmented frames can have more than EM_MAX_SCATTER segments. To handle the above EFBIG case, defragment the frame with m_defrag(9) and free the mbuf chain if it can't deframent the chain due to resource shortage. Reviewed by glebius (with improvements)
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/em/if_em.c45
1 files changed, 33 insertions, 12 deletions
diff --git a/sys/dev/em/if_em.c b/sys/dev/em/if_em.c
index 3f8792a..1a41390 100644
--- a/sys/dev/em/if_em.c
+++ b/sys/dev/em/if_em.c
@@ -1486,20 +1486,45 @@ 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_head, segs, &nsegs,
- BUS_DMA_NOWAIT);
- if (error != 0) {
+ error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, *m_headp, segs,
+ &nsegs, BUS_DMA_NOWAIT);
+ if (error == EFBIG) {
+ struct mbuf *m;
+
+ m = m_defrag(*m_headp, M_DONTWAIT);
+ if (m == NULL) {
+ /* Assume m_defrag(9) used only m_get(9). */
+ adapter->mbuf_alloc_failed++;
+ m_freem(*m_headp);
+ *m_headp = NULL;
+ return (ENOBUFS);
+ }
+ *m_headp = m;
+ error = bus_dmamap_load_mbuf_sg(adapter->txtag, map, *m_headp,
+ segs, &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ adapter->no_tx_dma_setup++;
+ m_freem(*m_headp);
+ *m_headp = NULL;
+ return (error);
+ }
+ } else if (error != 0) {
adapter->no_tx_dma_setup++;
return (error);
}
- KASSERT(nsegs != 0, ("em_encap: empty packet"));
+ if (nsegs == 0) {
+ m_freem(*m_headp);
+ *m_headp = NULL;
+ return (EIO);
+ }
if (nsegs > adapter->num_tx_desc_avail) {
adapter->no_tx_desc_avail2++;
- error = ENOBUFS;
- goto encap_fail;
+ bus_dmamap_unload(adapter->txtag, map);
+ return (ENOBUFS);
}
+ m_head = *m_headp;
if (ifp->if_hwassist > 0)
em_transmit_checksum_setup(adapter, m_head, &txd_upper, &txd_lower);
else
@@ -1526,8 +1551,8 @@ em_encap(struct adapter *adapter, struct mbuf **m_headp)
if (txd_used == adapter->num_tx_desc_avail) {
adapter->next_avail_tx_desc = txd_saved;
adapter->no_tx_desc_avail2++;
- error = ENOBUFS;
- goto encap_fail;
+ bus_dmamap_unload(adapter->txtag, map);
+ return (ENOBUFS);
}
tx_buffer = &adapter->tx_buffer_area[i];
current_tx_desc = &adapter->tx_desc_base[i];
@@ -1599,10 +1624,6 @@ em_encap(struct adapter *adapter, struct mbuf **m_headp)
}
return (0);
-
-encap_fail:
- bus_dmamap_unload(adapter->txtag, map);
- return (error);
}
/*********************************************************************
OpenPOWER on IntegriCloud