From 297f53342b73885fd27db30f6852e67f9a6c293a Mon Sep 17 00:00:00 2001 From: yongari Date: Mon, 14 Aug 2006 02:21:26 +0000 Subject: 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) --- sys/dev/em/if_em.c | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) (limited to 'sys/dev') 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); } /********************************************************************* -- cgit v1.1