diff options
author | Damien Bergamini <damien@cvs.openbsd.org> | 2008-12-21 18:19:59 +0000 |
---|---|---|
committer | Damien Bergamini <damien@cvs.openbsd.org> | 2008-12-21 18:19:59 +0000 |
commit | 7731f3f93e4d9f387f756d9c9093394fd7636524 (patch) | |
tree | b9b4a3e5770d66a19dd94b319555b31eab383e9f /sys/dev/pci/if_wpi.c | |
parent | a35971bc8438b357afff7f1214830daf00063b6a (diff) |
Undo m_defrag().
m_defrag() does not work. It seems to assume that if the length of
the mbuf passed as parameter is less than MHLEN, then it is an mbuf
header and not a cluster (or something like that.)
It thus fails miserably in the bcopy path.
I don't have the time to investigate further into this.
Thanks to Okan Demirmen for reporting the issue on a ral(4) RT2560.
The RT2560 chipset does not support TX scatter and thus m_defrag()
was called much more often than in other drivers using m_defrag()
where it was less noticeable.
Diffstat (limited to 'sys/dev/pci/if_wpi.c')
-rw-r--r-- | sys/dev/pci/if_wpi.c | 21 |
1 files changed, 18 insertions, 3 deletions
diff --git a/sys/dev/pci/if_wpi.c b/sys/dev/pci/if_wpi.c index 561714f1599..3fed5f6112e 100644 --- a/sys/dev/pci/if_wpi.c +++ b/sys/dev/pci/if_wpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_wpi.c,v 1.78 2008/12/03 17:17:08 damien Exp $ */ +/* $OpenBSD: if_wpi.c,v 1.79 2008/12/21 18:19:58 damien Exp $ */ /*- * Copyright (c) 2006-2008 @@ -1687,6 +1687,7 @@ wpi_tx(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni) const struct wpi_rate *rinfo; struct ieee80211_frame *wh; struct ieee80211_key *k = NULL; + struct mbuf *m1; enum ieee80211_edca_ac ac; uint32_t flags; uint16_t qos; @@ -1865,10 +1866,24 @@ wpi_tx(struct wpi_softc *sc, struct mbuf *m, struct ieee80211_node *ni) } if (error != 0) { /* Too many DMA segments, linearize mbuf. */ - if (m_defrag(m, M_DONTWAIT) != 0) { + MGETHDR(m1, MT_DATA, M_DONTWAIT); + if (m1 == NULL) { m_freem(m); - return ENOMEM; + return ENOBUFS; + } + if (m->m_pkthdr.len > MHLEN) { + MCLGET(m1, M_DONTWAIT); + if (!(m1->m_flags & M_EXT)) { + m_freem(m); + m_freem(m1); + return ENOBUFS; + } } + m_copydata(m, 0, m->m_pkthdr.len, mtod(m1, caddr_t)); + m1->m_pkthdr.len = m1->m_len = m->m_pkthdr.len; + m_freem(m); + m = m1; + error = bus_dmamap_load_mbuf(sc->sc_dmat, data->map, m, BUS_DMA_NOWAIT); if (error != 0) { |