diff options
author | glebius <glebius@FreeBSD.org> | 2006-08-17 09:53:04 +0000 |
---|---|---|
committer | glebius <glebius@FreeBSD.org> | 2006-08-17 09:53:04 +0000 |
commit | be3d72f3831380ca74c38412b4a6d394afa08039 (patch) | |
tree | 4e8282bb8fd7f6d19bd91bc52f5a74cc93fb5b61 /sys/dev/bge | |
parent | a6834221aa1bc6393fa7b599bc7182a149c8c037 (diff) | |
download | FreeBSD-src-be3d72f3831380ca74c38412b4a6d394afa08039.zip FreeBSD-src-be3d72f3831380ca74c38412b4a6d394afa08039.tar.gz |
Rewrite bge_encap() so that it takes mbuf ** argument. In this case if
m_defrag(9) changes pointer we can show this to our caller.
Reviewed by: yongari
Diffstat (limited to 'sys/dev/bge')
-rw-r--r-- | sys/dev/bge/if_bge.c | 86 |
1 files changed, 48 insertions, 38 deletions
diff --git a/sys/dev/bge/if_bge.c b/sys/dev/bge/if_bge.c index ab6151e..bafe61e 100644 --- a/sys/dev/bge/if_bge.c +++ b/sys/dev/bge/if_bge.c @@ -330,7 +330,7 @@ static void bge_tick_locked(struct bge_softc *); static void bge_tick(void *); static void bge_stats_update(struct bge_softc *); static void bge_stats_update_regs(struct bge_softc *); -static int bge_encap(struct bge_softc *, struct mbuf *, uint32_t *); +static int bge_encap(struct bge_softc *, struct mbuf **, uint32_t *); static void bge_intr(void *); static void bge_start_locked(struct ifnet *); @@ -2894,50 +2894,37 @@ bge_cksum_pad(struct mbuf *m) * pointers to descriptors. */ static int -bge_encap(struct bge_softc *sc, struct mbuf *m_head, uint32_t *txidx) +bge_encap(struct bge_softc *sc, struct mbuf **m_head, uint32_t *txidx) { bus_dma_segment_t segs[BGE_NSEG_NEW]; bus_dmamap_t map; - struct bge_tx_bd *d = NULL; + struct bge_tx_bd *d; + struct mbuf *m = *m_head; struct m_tag *mtag; uint32_t idx = *txidx; - uint16_t csum_flags = 0; + uint16_t csum_flags; int nsegs, i, error; - if (m_head->m_pkthdr.csum_flags) { - if (m_head->m_pkthdr.csum_flags & CSUM_IP) - csum_flags |= BGE_TXBDFLAG_IP_CSUM; - if (m_head->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) { - csum_flags |= BGE_TXBDFLAG_TCP_UDP_CSUM; - if (m_head->m_pkthdr.len < ETHER_MIN_NOPAD && - bge_cksum_pad(m_head) != 0) - return (ENOBUFS); - } - if (m_head->m_flags & M_LASTFRAG) - csum_flags |= BGE_TXBDFLAG_IP_FRAG_END; - else if (m_head->m_flags & M_FRAG) - csum_flags |= BGE_TXBDFLAG_IP_FRAG; - } - - mtag = VLAN_OUTPUT_TAG(sc->bge_ifp, m_head); - 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); + error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_mtag, map, m, segs, + &nsegs, BUS_DMA_NOWAIT); + if (error == EFBIG) { + m = m_defrag(m, M_DONTWAIT); + if (m == NULL) { + m_freem(*m_head); + *m_head = NULL; + return (ENOBUFS); } - if (error) + *m_head = m; + error = bus_dmamap_load_mbuf_sg(sc->bge_cdata.bge_mtag, map, m, + segs, &nsegs, BUS_DMA_NOWAIT); + if (error) { + m_freem(m); + *m_head = NULL; return (error); - } + } + } else if (error != 0) + return (error); /* * Sanity check: avoid coming within 16 descriptors @@ -2948,6 +2935,26 @@ bge_encap(struct bge_softc *sc, struct mbuf *m_head, uint32_t *txidx) return (ENOBUFS); } + csum_flags = 0; + if (m->m_pkthdr.csum_flags) { + if (m->m_pkthdr.csum_flags & CSUM_IP) + csum_flags |= BGE_TXBDFLAG_IP_CSUM; + if (m->m_pkthdr.csum_flags & (CSUM_TCP | CSUM_UDP)) { + csum_flags |= BGE_TXBDFLAG_TCP_UDP_CSUM; + if (m->m_pkthdr.len < ETHER_MIN_NOPAD && + (error = bge_cksum_pad(m)) != 0) { + bus_dmamap_unload(sc->bge_cdata.bge_mtag, map); + m_freem(m); + *m_head = NULL; + return (error); + } + } + if (m->m_flags & M_LASTFRAG) + csum_flags |= BGE_TXBDFLAG_IP_FRAG_END; + else if (m->m_flags & M_FRAG) + csum_flags |= BGE_TXBDFLAG_IP_FRAG; + } + bus_dmamap_sync(sc->bge_cdata.bge_mtag, map, BUS_DMASYNC_PREWRITE); for (i = 0; ; i++) { @@ -2963,9 +2970,10 @@ bge_encap(struct bge_softc *sc, struct mbuf *m_head, uint32_t *txidx) /* 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) { + if ((mtag = VLAN_OUTPUT_TAG(sc->bge_ifp, m)) != NULL) { d->bge_flags |= BGE_TXBDFLAG_VLAN_TAG; d->bge_vlan_tag = VLAN_TAG_VALUE(mtag); } else @@ -2978,7 +2986,7 @@ bge_encap(struct bge_softc *sc, struct mbuf *m_head, uint32_t *txidx) */ 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_cdata.bge_tx_chain[idx] = m; sc->bge_txcnt += nsegs; BGE_INC(idx, BGE_TX_RING_CNT); @@ -3039,7 +3047,9 @@ bge_start_locked(struct ifnet *ifp) * don't have room, set the OACTIVE flag and wait * for the NIC to drain the ring. */ - if (bge_encap(sc, m_head, &prodidx)) { + if (bge_encap(sc, &m_head, &prodidx)) { + if (m_head == NULL) + break; IFQ_DRV_PREPEND(&ifp->if_snd, m_head); ifp->if_drv_flags |= IFF_DRV_OACTIVE; break; |