diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2004-12-06 20:27:16 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2004-12-06 20:27:16 +0000 |
commit | cb8b8cb5df5015df984897265e1dcbf9a0b58be6 (patch) | |
tree | 9c8a6a55418dda2805ade2c22d25407d93b62baa | |
parent | 2c3e989235c64a19af4cfa32ca043a132f3f5f63 (diff) |
add mbuf linearization code when the number of fragments exceeds what is
supported by the hardware
-rw-r--r-- | sys/dev/pci/if_ipw.c | 36 | ||||
-rw-r--r-- | sys/dev/pci/if_iwi.c | 36 |
2 files changed, 68 insertions, 4 deletions
diff --git a/sys/dev/pci/if_ipw.c b/sys/dev/pci/if_ipw.c index 4f727f84d6d..7f0dbec6c59 100644 --- a/sys/dev/pci/if_ipw.c +++ b/sys/dev/pci/if_ipw.c @@ -1,4 +1,4 @@ -/* $Id: if_ipw.c,v 1.34 2004/12/05 20:19:30 damien Exp $ */ +/* $Id: if_ipw.c,v 1.35 2004/12/06 20:27:15 damien Exp $ */ /*- * Copyright (c) 2004 @@ -1160,6 +1160,7 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni) struct ipw_soft_bd *sbd; struct ipw_soft_hdr *shdr; struct ipw_soft_buf *sbuf; + struct mbuf *mnew; int error, i; if (ic->ic_flags & IEEE80211_F_WEPON) { @@ -1208,12 +1209,43 @@ ipw_tx_start(struct ifnet *ifp, struct mbuf *m, struct ieee80211_node *ni) m_adj(m, sizeof (struct ieee80211_frame)); error = bus_dmamap_load_mbuf(sc->sc_dmat, sbuf->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, sbuf->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; + } + } error = bus_dmamap_load(sc->sc_dmat, shdr->map, &shdr->hdr, sizeof (struct ipw_hdr), NULL, BUS_DMA_NOWAIT); 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; |