diff options
author | glebius <glebius@FreeBSD.org> | 2005-12-15 09:45:53 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2005-12-15 09:45:53 +0000 |
commit | ba9bfc2a41efb40a30484df932585c12de79101f (patch) | |
tree | 76f9ed1f226099f26771c7639420ee98da7d38ba /sys/dev/bge | |
parent | 653c0a23d7bb507ef9ab20b75368adc642b87366 (diff) | |
download | FreeBSD-src-ba9bfc2a41efb40a30484df932585c12de79101f.zip FreeBSD-src-ba9bfc2a41efb40a30484df932585c12de79101f.tar.gz |
o Rewrite bge_encap() to use bus_dmamap_load_mbuf_sg(9), inlining the
callback function bge_dma_map_tx_desc() into the bge_encap() itself.
o If busdma returns EFBIG, try to m_defrag() the packet.
Reviewed by: yongari
Diffstat (limited to 'sys/dev/bge')
-rw-r--r-- | sys/dev/bge/if_bge.c | 137 |
1 files changed, 55 insertions, 82 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c index ea32a1d..f76309b 100644 --- a/sys/dev/bge/if_bge.c +++ b/sys/dev/bge/if_bge.c @@ -202,8 +202,6 @@ static int bge_resume (device_t); static void bge_release_resources (struct bge_softc *); static void bge_dma_map_addr (void *, bus_dma_segment_t *, int, int); -static void bge_dma_map_tx_desc (void *, bus_dma_segment_t *, int, - bus_size_t, int); static int bge_dma_alloc (device_t); static void bge_dma_free (struct bge_softc *); @@ -394,53 +392,6 @@ bge_dma_map_addr(arg, segs, nseg, error) return; } -/* - * Map an mbuf chain into an TX ring. - */ - -static void -bge_dma_map_tx_desc(arg, segs, nseg, mapsize, error) - void *arg; - bus_dma_segment_t *segs; - int nseg; - bus_size_t mapsize; - int error; -{ - struct bge_dmamap_arg *ctx; - struct bge_tx_bd *d = NULL; - int i = 0, idx; - - if (error) - return; - - ctx = arg; - - /* Signal error to caller if there's too many segments */ - if (nseg > ctx->bge_maxsegs) { - ctx->bge_maxsegs = 0; - return; - } - - idx = ctx->bge_idx; - while(1) { - d = &ctx->bge_ring[idx]; - d->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[i].ds_addr); - d->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[i].ds_addr); - d->bge_len = segs[i].ds_len; - d->bge_flags = ctx->bge_flags; - i++; - if (i == nseg) - break; - BGE_INC(idx, BGE_TX_RING_CNT); - } - - d->bge_flags |= BGE_TXBDFLAG_END; - ctx->bge_maxsegs = nseg; - ctx->bge_idx = idx; - - return; -} - #ifdef notdef static u_int8_t bge_vpd_readbyte(sc, addr) @@ -2989,15 +2940,15 @@ static int bge_encap(sc, m_head, txidx) struct bge_softc *sc; struct mbuf *m_head; - u_int32_t *txidx; + uint32_t *txidx; { - struct bge_tx_bd *f = NULL; - u_int16_t csum_flags = 0; - struct m_tag *mtag; - struct bge_dmamap_arg ctx; + bus_dma_segment_t segs[BGE_NSEG_NEW]; bus_dmamap_t map; - int error; - + struct bge_tx_bd *d = NULL; + struct m_tag *mtag; + uint32_t idx = *txidx; + uint16_t csum_flags = 0; + int nsegs, i, error; if (m_head->m_pkthdr.csum_flags) { if (m_head->m_pkthdr.csum_flags & CSUM_IP) @@ -3012,46 +2963,68 @@ bge_encap(sc, m_head, txidx) mtag = VLAN_OUTPUT_TAG(sc->bge_ifp, m_head); - ctx.sc = sc; - ctx.bge_idx = *txidx; - ctx.bge_ring = sc->bge_ldata.bge_tx_ring; - ctx.bge_flags = csum_flags; + map = sc->bge_cdata.bge_tx_dmamap[idx]; + error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_mtag, map, + m_head, segs, &nsegs, BUS_DMA_NOWAIT); + if (error) { + if (error == EFBIG) { + struct mbuf *m0; + + m0 = m_defrag(m_head, M_DONTWAIT); + if (m0 == NULL) + return (ENOBUFS); + m_head = m0; + error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_mtag, + map, m_head, segs, &nsegs, BUS_DMA_NOWAIT); + } + if (error) + return (error); + } + /* * Sanity check: avoid coming within 16 descriptors * of the end of the ring. */ - ctx.bge_maxsegs = (BGE_TX_RING_CNT - sc->bge_txcnt) - 16; + if (nsegs > (BGE_TX_RING_CNT - sc->bge_txcnt - 16)) { + bus_dmamap_unload(sc->bge_cdata.bge_mtag, map); + return (ENOBUFS); + } - map = sc->bge_cdata.bge_tx_dmamap[*txidx]; - error = bus_dmamap_load_mbuf(sc->bge_cdata.bge_mtag, map, - m_head, bge_dma_map_tx_desc, &ctx, BUS_DMA_NOWAIT); + for (i = 0; ; i++) { + d = &sc->bge_ldata.bge_tx_ring[idx]; + d->bge_addr.bge_addr_lo = BGE_ADDR_LO(segs[i].ds_addr); + d->bge_addr.bge_addr_hi = BGE_ADDR_HI(segs[i].ds_addr); + d->bge_len = segs[i].ds_len; + d->bge_flags = csum_flags; + if (i == nsegs - 1) + break; + BGE_INC(idx, BGE_TX_RING_CNT); + } - if (error || ctx.bge_maxsegs == 0 /*|| - ctx.bge_idx == sc->bge_tx_saved_considx*/) - return (ENOBUFS); + /* Mark the last segment as end of packet... */ + d->bge_flags |= BGE_TXBDFLAG_END; + /* ... and put VLAN tag into first segment. */ + d = &sc->bge_ldata.bge_tx_ring[*txidx]; + if (mtag != NULL) { + d->bge_flags |= BGE_TXBDFLAG_VLAN_TAG; + d->bge_vlan_tag = VLAN_TAG_VALUE(mtag); + } else + d->bge_vlan_tag = 0; /* * Insure that the map for this transmission * is placed at the array index of the last descriptor * in this chain. */ - sc->bge_cdata.bge_tx_dmamap[*txidx] = - sc->bge_cdata.bge_tx_dmamap[ctx.bge_idx]; - sc->bge_cdata.bge_tx_dmamap[ctx.bge_idx] = map; - sc->bge_cdata.bge_tx_chain[ctx.bge_idx] = m_head; - sc->bge_txcnt += ctx.bge_maxsegs; - f = &sc->bge_ldata.bge_tx_ring[*txidx]; - if (mtag != NULL) { - f->bge_flags |= BGE_TXBDFLAG_VLAN_TAG; - f->bge_vlan_tag = VLAN_TAG_VALUE(mtag); - } else { - f->bge_vlan_tag = 0; - } + sc->bge_cdata.bge_tx_dmamap[*txidx] = sc->bge_cdata.bge_tx_dmamap[idx]; + sc->bge_cdata.bge_tx_dmamap[idx] = map; + sc->bge_cdata.bge_tx_chain[idx] = m_head; + sc->bge_txcnt += nsegs; - BGE_INC(ctx.bge_idx, BGE_TX_RING_CNT); - *txidx = ctx.bge_idx; + BGE_INC(idx, BGE_TX_RING_CNT); + *txidx = idx; - return(0); + return (0); } /* |