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
This commit is contained in:
glebius 2006-08-17 09:53:04 +00:00
parent a6834221aa
commit be3d72f383

View File

@ -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;