From cb8b8cb5df5015df984897265e1dcbf9a0b58be6 Mon Sep 17 00:00:00 2001 From: Damien Bergamini Date: Mon, 6 Dec 2004 20:27:16 +0000 Subject: add mbuf linearization code when the number of fragments exceeds what is supported by the hardware --- sys/dev/pci/if_ipw.c | 36 ++++++++++++++++++++++++++++++++++-- sys/dev/pci/if_iwi.c | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 68 insertions(+), 4 deletions(-) (limited to 'sys/dev') 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; -- cgit v1.2.3