diff options
Diffstat (limited to 'sys/dev/pci/if_iwi.c')
-rw-r--r-- | sys/dev/pci/if_iwi.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/sys/dev/pci/if_iwi.c b/sys/dev/pci/if_iwi.c index 2911319d38b..c16666b40f7 100644 --- a/sys/dev/pci/if_iwi.c +++ b/sys/dev/pci/if_iwi.c @@ -1,4 +1,4 @@ -/* $Id: if_iwi.c,v 1.19 2004/12/06 19:58:44 damien Exp $ */ +/* $Id: if_iwi.c,v 1.20 2004/12/06 20:27:15 damien Exp $ */ /*- * Copyright (c) 2004 @@ -1026,6 +1026,7 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni) struct ieee80211_frame *wh; struct iwi_tx_buf *buf; struct iwi_tx_desc *desc; + struct mbuf *mnew; int error, i; #if NBPFILTER > 0 @@ -1055,12 +1056,43 @@ iwi_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni) desc = &sc->tx_desc[sc->tx_cur]; error = bus_dmamap_load_mbuf(sc->sc_dmat, buf->map, m, BUS_DMA_NOWAIT); - if (error != 0) { + if (error != 0 && error != EFBIG) { printf("%s: could not map mbuf (error %d)\n", sc->sc_dev.dv_xname, error); m_freem(m); return error; } + if (error != 0) { + /* too many fragments, linearize */ + + MGETHDR(mnew, M_DONTWAIT, MT_DATA); + if (mnew == NULL) { + m_freem(m); + return ENOMEM; + } + + M_DUP_PKTHDR(mnew, m); + MCLGET(mnew, M_DONTWAIT); + if (!(mnew->m_flags & M_EXT)) { + m_freem(m); + m_freem(mnew); + return ENOMEM; + } + + m_copydata(m, 0, m->m_pkthdr.len, mtod(mnew, caddr_t)); + m_freem(m); + m->m_len = m->m_pkthdr.len; + m = mnew; + + error = bus_dmamap_load_mbuf(sc->sc_dmat, buf->map, m, + BUS_DMA_NOWAIT); + if (error != 0) { + printf("%s: could not map mbuf (error %d)\n", + sc->sc_dev.dv_xname, error); + m_freem(m); + return error; + } + } buf->m = m; buf->ni = ni; |