diff options
author | David Gwynne <dlg@cvs.openbsd.org> | 2015-11-09 00:22:58 +0000 |
---|---|---|
committer | David Gwynne <dlg@cvs.openbsd.org> | 2015-11-09 00:22:58 +0000 |
commit | d1a8c3966d4b13ef9211587439a4896144eafcf1 (patch) | |
tree | 63c6733a18dc85fc28c72d2c1429d6f9542273be | |
parent | 6075612265a17991a15247cfb927f15b97435610 (diff) |
rework the code to avoid IF_PREPEND.
IF_PREPEND assumes the underlying send queue is using priq, so if you're
using hfsc things dont work well.
part of this shuffle moved the defragmentation of the mbuf to using
m_defrag instead of hand rolled code.
tested by several people on tech@
-rw-r--r-- | sys/dev/pci/if_vr.c | 101 |
1 files changed, 43 insertions, 58 deletions
diff --git a/sys/dev/pci/if_vr.c b/sys/dev/pci/if_vr.c index 6fe6fc12a9d..a8a71beb680 100644 --- a/sys/dev/pci/if_vr.c +++ b/sys/dev/pci/if_vr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_vr.c,v 1.144 2015/10/25 13:04:28 mpi Exp $ */ +/* $OpenBSD: if_vr.c,v 1.145 2015/11/09 00:22:57 dlg Exp $ */ /* * Copyright (c) 1997, 1998 @@ -1185,62 +1185,51 @@ vr_intr(void *arg) * pointers to the fragment pointers. */ int -vr_encap(struct vr_softc *sc, struct vr_chain **cp, struct mbuf *m_head) +vr_encap(struct vr_softc *sc, struct vr_chain **cp, struct mbuf *m) { struct vr_chain *c = *cp; struct vr_desc *f = NULL; - struct mbuf *m_new = NULL; u_int32_t vr_ctl = 0, vr_status = 0, intdisable = 0; bus_dmamap_t txmap; int i, runt = 0; + int error; if (sc->vr_quirks & VR_Q_CSUM) { - if (m_head->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) + if (m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT) vr_ctl |= VR_TXCTL_IPCSUM; - if (m_head->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) + if (m->m_pkthdr.csum_flags & M_TCP_CSUM_OUT) vr_ctl |= VR_TXCTL_TCPCSUM; - if (m_head->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) + if (m->m_pkthdr.csum_flags & M_UDP_CSUM_OUT) vr_ctl |= VR_TXCTL_UDPCSUM; } - /* Deep copy for chips that need alignment, or too many segments */ - if (sc->vr_quirks & VR_Q_NEEDALIGN || - bus_dmamap_load_mbuf(sc->sc_dmat, c->vr_map, m_head, - BUS_DMA_NOWAIT | BUS_DMA_WRITE)) { - MGETHDR(m_new, M_DONTWAIT, MT_DATA); - if (m_new == NULL) - return (1); - if (m_head->m_pkthdr.len > MHLEN) { - MCLGET(m_new, M_DONTWAIT); - if (!(m_new->m_flags & M_EXT)) { - m_freem(m_new); - return (1); - } - } - m_copydata(m_head, 0, m_head->m_pkthdr.len, - mtod(m_new, caddr_t)); - m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len; - - if (bus_dmamap_load_mbuf(sc->sc_dmat, c->vr_map, m_new, - BUS_DMA_NOWAIT | BUS_DMA_WRITE)) { - m_freem(m_new); - return(1); - } + if (sc->vr_quirks & VR_Q_NEEDALIGN) { + /* Deep copy for chips that need alignment */ + error = EFBIG; + } else { + error = bus_dmamap_load_mbuf(sc->sc_dmat, c->vr_map, m, + BUS_DMA_NOWAIT | BUS_DMA_WRITE); } + switch (error) { + case 0: + break; + case EFBIG: + if (m_defrag(m, M_DONTWAIT) == 0 && + bus_dmamap_load_mbuf(sc->sc_dmat, c->vr_map, m, + BUS_DMA_NOWAIT) == 0) + break; + + /* FALLTHROUGH */ + default: + return (ENOBUFS); + } + bus_dmamap_sync(sc->sc_dmat, c->vr_map, 0, c->vr_map->dm_mapsize, BUS_DMASYNC_PREWRITE); if (c->vr_map->dm_mapsize < VR_MIN_FRAMELEN) runt = 1; - /* Check number of available descriptors */ - if (sc->vr_cdata.vr_tx_cnt + c->vr_map->dm_nsegs + runt >= - (VR_TX_LIST_CNT - 1)) { - if (m_new) - m_freem(m_new); - return(1); - } - #if NVLAN > 0 /* * Tell chip to insert VLAN tag if needed. @@ -1248,8 +1237,8 @@ vr_encap(struct vr_softc *sc, struct vr_chain **cp, struct mbuf *m_head) * in only 15 bits without the gap at 0x1000 (reserved for DEI). * Therefore we need to de- / re-construct the VLAN header. */ - if (m_head->m_flags & M_VLANTAG) { - u_int32_t vtag = m_head->m_pkthdr.ether_vtag; + if (m->m_flags & M_VLANTAG) { + u_int32_t vtag = m->m_pkthdr.ether_vtag; vtag = EVL_VLANOFTAG(vtag) | EVL_PRIOFTAG(vtag) << 12; vr_status |= vtag << VR_TXSTAT_PQSHIFT; vr_ctl |= htole32(VR_TXCTL_INSERTTAG); @@ -1268,12 +1257,7 @@ vr_encap(struct vr_softc *sc, struct vr_chain **cp, struct mbuf *m_head) sc->vr_quirks & VR_Q_INTDISABLE) intdisable = VR_TXNEXT_INTDISABLE; - if (m_new != NULL) { - m_freem(m_head); - - c->vr_mbuf = m_new; - } else - c->vr_mbuf = m_head; + c->vr_mbuf = m; txmap = c->vr_map; for (i = 0; i < txmap->dm_nsegs; i++) { if (i != 0) @@ -1321,7 +1305,7 @@ void vr_start(struct ifnet *ifp) { struct vr_softc *sc; - struct mbuf *m_head; + struct mbuf *m; struct vr_chain *cur_tx, *head_tx; unsigned int queued = 0; @@ -1334,17 +1318,22 @@ vr_start(struct ifnet *ifp) return; cur_tx = sc->vr_cdata.vr_tx_prod; - while (cur_tx->vr_mbuf == NULL) { - IFQ_DEQUEUE(&ifp->if_snd, m_head); - if (m_head == NULL) + for (;;) { + if (sc->vr_cdata.vr_tx_cnt + VR_MAXFRAGS >= + VR_TX_LIST_CNT - 1) { + ifp->if_flags |= IFF_OACTIVE; + break; + } + + IFQ_DEQUEUE(&ifp->if_snd, m); + if (m== NULL) break; /* Pack the data into the descriptor. */ head_tx = cur_tx; - if (vr_encap(sc, &cur_tx, m_head)) { - /* Rollback, send what we were able to encap. */ - IF_PREPEND(&ifp->if_snd, m_head); - break; + if (vr_encap(sc, &cur_tx, m)) { + ifp->if_oerrors++; + continue; } queued++; @@ -1357,8 +1346,7 @@ vr_start(struct ifnet *ifp) * to him. */ if (ifp->if_bpf) - bpf_mtap_ether(ifp->if_bpf, head_tx->vr_mbuf, - BPF_DIRECTION_OUT); + bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT); #endif cur_tx = cur_tx->vr_nextdesc; } @@ -1374,9 +1362,6 @@ vr_start(struct ifnet *ifp) /* Set a timeout in case the chip goes out to lunch. */ ifp->if_timer = 5; - - if (cur_tx->vr_mbuf != NULL) - ifp->if_flags |= IFF_OACTIVE; } } |