summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Bergamini <damien@cvs.openbsd.org>2004-12-06 20:27:16 +0000
committerDamien Bergamini <damien@cvs.openbsd.org>2004-12-06 20:27:16 +0000
commitcb8b8cb5df5015df984897265e1dcbf9a0b58be6 (patch)
tree9c8a6a55418dda2805ade2c22d25407d93b62baa
parent2c3e989235c64a19af4cfa32ca043a132f3f5f63 (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.c36
-rw-r--r--sys/dev/pci/if_iwi.c36
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;