summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbschmidt <bschmidt@FreeBSD.org>2011-04-16 10:32:46 +0000
committerbschmidt <bschmidt@FreeBSD.org>2011-04-16 10:32:46 +0000
commit7c20ac5e151fd7bf876c5ae92b96c3da95cd6dcd (patch)
tree06a7a66120a674c3e8aba202cfd629c00aa05b62
parent021ca1d5e8c2837f4accb324675486959e007579 (diff)
downloadFreeBSD-src-7c20ac5e151fd7bf876c5ae92b96c3da95cd6dcd.zip
FreeBSD-src-7c20ac5e151fd7bf876c5ae92b96c3da95cd6dcd.tar.gz
Rewrite DMA segment handling to be more inline with the OpenBSD code.
Also change the m_len == 0 hack to have less code churn.
-rw-r--r--sys/dev/iwn/if_iwn.c108
1 files changed, 62 insertions, 46 deletions
diff --git a/sys/dev/iwn/if_iwn.c b/sys/dev/iwn/if_iwn.c
index 6d62f3a..0f35d6c 100644
--- a/sys/dev/iwn/if_iwn.c
+++ b/sys/dev/iwn/if_iwn.c
@@ -2906,8 +2906,8 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
struct iwn_cmd_data *tx;
struct ieee80211_frame *wh;
struct ieee80211_key *k = NULL;
- struct mbuf *mnew;
- bus_dma_segment_t segs[IWN_MAX_SCATTER];
+ struct mbuf *m1;
+ bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER];
uint32_t flags;
u_int hdrlen;
int totlen, error, pad, nsegs = 0, i, rate;
@@ -3063,26 +3063,30 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
tx->security = 0;
tx->flags = htole32(flags);
- if (m->m_len > 0) {
- error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map,
- m, segs, &nsegs, BUS_DMA_NOWAIT);
- if (error == EFBIG) {
- /* too many fragments, linearize */
- mnew = m_collapse(m, M_DONTWAIT, IWN_MAX_SCATTER);
- if (mnew == NULL) {
- device_printf(sc->sc_dev,
- "%s: could not defrag mbuf\n", __func__);
- m_freem(m);
- return ENOBUFS;
- }
- m = mnew;
- error = bus_dmamap_load_mbuf_sg(ring->data_dmat,
- data->map, m, segs, &nsegs, BUS_DMA_NOWAIT);
+ error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs,
+ &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if (error != EFBIG) {
+ device_printf(sc->sc_dev,
+ "%s: can't map mbuf (error %d)\n", __func__, error);
+ m_freem(m);
+ return error;
}
+ /* Too many DMA segments, linearize mbuf. */
+ m1 = m_collapse(m, M_DONTWAIT, IWN_MAX_SCATTER);
+ if (m1 == NULL) {
+ device_printf(sc->sc_dev,
+ "%s: could not defrag mbuf\n", __func__);
+ m_freem(m);
+ return ENOBUFS;
+ }
+ m = m1;
+
+ error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m,
+ segs, &nsegs, BUS_DMA_NOWAIT);
if (error != 0) {
device_printf(sc->sc_dev,
- "%s: bus_dmamap_load_mbuf_sg failed, error %d\n",
- __func__, error);
+ "%s: can't map mbuf (error %d)\n", __func__, error);
m_freem(m);
return error;
}
@@ -3095,16 +3099,20 @@ iwn_tx_data(struct iwn_softc *sc, struct mbuf *m, struct ieee80211_node *ni,
__func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs);
/* Fill TX descriptor. */
- desc->nsegs = 1 + nsegs;
+ desc->nsegs = 1;
+ if (m->m_len != 0)
+ desc->nsegs += nsegs;
/* First DMA segment is used by the TX command. */
desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr));
desc->segs[0].len = htole16(IWN_HIADDR(data->cmd_paddr) |
(4 + sizeof (*tx) + hdrlen + pad) << 4);
/* Other DMA segments are for data payload. */
+ seg = &segs[0];
for (i = 1; i <= nsegs; i++) {
- desc->segs[i].addr = htole32(IWN_LOADDR(segs[i - 1].ds_addr));
- desc->segs[i].len = htole16(IWN_HIADDR(segs[i - 1].ds_addr) |
- segs[i - 1].ds_len << 4);
+ desc->segs[i].addr = htole32(IWN_LOADDR(seg->ds_addr));
+ desc->segs[i].len = htole16(IWN_HIADDR(seg->ds_addr) |
+ seg->ds_len << 4);
+ seg++;
}
bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
@@ -3144,8 +3152,8 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
struct ieee80211_frame *wh;
struct iwn_tx_desc *desc;
struct iwn_tx_data *data;
- struct mbuf *mnew;
- bus_dma_segment_t segs[IWN_MAX_SCATTER];
+ struct mbuf *m1;
+ bus_dma_segment_t *seg, segs[IWN_MAX_SCATTER];
uint32_t flags;
u_int hdrlen;
int totlen, error, pad, nsegs = 0, i, rate;
@@ -3256,26 +3264,30 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
tx->security = 0;
tx->flags = htole32(flags);
- if (m->m_len > 0) {
- error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map,
- m, segs, &nsegs, BUS_DMA_NOWAIT);
- if (error == EFBIG) {
- /* Too many fragments, linearize. */
- mnew = m_collapse(m, M_DONTWAIT, IWN_MAX_SCATTER);
- if (mnew == NULL) {
- device_printf(sc->sc_dev,
- "%s: could not defrag mbuf\n", __func__);
- m_freem(m);
- return ENOBUFS;
- }
- m = mnew;
- error = bus_dmamap_load_mbuf_sg(ring->data_dmat,
- data->map, m, segs, &nsegs, BUS_DMA_NOWAIT);
+ error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m, segs,
+ &nsegs, BUS_DMA_NOWAIT);
+ if (error != 0) {
+ if (error != EFBIG) {
+ device_printf(sc->sc_dev,
+ "%s: can't map mbuf (error %d)\n", __func__, error);
+ m_freem(m);
+ return error;
}
+ /* Too many DMA segments, linearize mbuf. */
+ m1 = m_collapse(m, M_DONTWAIT, IWN_MAX_SCATTER);
+ if (m1 == NULL) {
+ device_printf(sc->sc_dev,
+ "%s: could not defrag mbuf\n", __func__);
+ m_freem(m);
+ return ENOBUFS;
+ }
+ m = m1;
+
+ error = bus_dmamap_load_mbuf_sg(ring->data_dmat, data->map, m,
+ segs, &nsegs, BUS_DMA_NOWAIT);
if (error != 0) {
device_printf(sc->sc_dev,
- "%s: bus_dmamap_load_mbuf_sg failed, error %d\n",
- __func__, error);
+ "%s: can't map mbuf (error %d)\n", __func__, error);
m_freem(m);
return error;
}
@@ -3288,16 +3300,20 @@ iwn_tx_data_raw(struct iwn_softc *sc, struct mbuf *m,
__func__, ring->qid, ring->cur, m->m_pkthdr.len, nsegs);
/* Fill TX descriptor. */
- desc->nsegs = 1 + nsegs;
+ desc->nsegs = 1;
+ if (m->m_len != 0)
+ desc->nsegs += nsegs;
/* First DMA segment is used by the TX command. */
desc->segs[0].addr = htole32(IWN_LOADDR(data->cmd_paddr));
desc->segs[0].len = htole16(IWN_HIADDR(data->cmd_paddr) |
(4 + sizeof (*tx) + hdrlen + pad) << 4);
/* Other DMA segments are for data payload. */
+ seg = &segs[0];
for (i = 1; i <= nsegs; i++) {
- desc->segs[i].addr = htole32(IWN_LOADDR(segs[i - 1].ds_addr));
- desc->segs[i].len = htole16(IWN_HIADDR(segs[i - 1].ds_addr) |
- segs[i - 1].ds_len << 4);
+ desc->segs[i].addr = htole32(IWN_LOADDR(seg->ds_addr));
+ desc->segs[i].len = htole16(IWN_HIADDR(seg->ds_addr) |
+ seg->ds_len << 4);
+ seg++;
}
bus_dmamap_sync(ring->data_dmat, data->map, BUS_DMASYNC_PREWRITE);
OpenPOWER on IntegriCloud