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)
This commit is contained in:
Pyun YongHyeon 2006-08-14 02:21:26 +00:00
parent f1909c6f53
commit 4f74b4e080
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=161267

View File

@ -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);
}
/*********************************************************************