On Wed, 6 Jan 2016, Mike Belopuhov wrote:

> There's still stuff to do, but it receives and transmits reliably
> (at least on modern Xen) so I'd like to get it in.  Man page will
> follow.

I only had a quick glance at the code, but I have one comment about your 
use of memory barriers. The membar_* macros are pure compiler barriers 
when the openbsd kernel is compiled for UP. But since the host machine and 
xen may use SMP even in this case, I suspect the that you need hardware 
memory barriers even if MULTIPROCESSOR is not defined. This does not seem 
relevant for x86 because you don't use membar_sync, but it may become 
relevant for arm, which is also supported by xen.

I had the same problem in virtio and introduced the virtio_membar_* macros 
for this purpose. Maybe they should be renamed to a more generic name and 
you should use them, too?


> +     if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
> +             return;
> +
> +     prod = txr->txr_prod;
> +     membar_consumer();
> +
> +     for (;;) {
> +             m = ifq_deq_begin(&ifp->if_snd);
> +             if (m == NULL)
> +                     break;
> +
> +             error = xnf_encap(sc, m, &prod);
> +             if (error == ENOENT) {
> +                     /* transient */
> +                     ifq_deq_rollback(&ifp->if_snd, m);
> +                     ifq_set_oactive(&ifp->if_snd);
> +                     break;
> +             } else if (error) {
> +                     /* the chain is too large */
> +                     ifq_deq_commit(&ifp->if_snd, m);
> +                     m_freem(m);
> +                     continue;
> +             }
> +             ifq_deq_commit(&ifp->if_snd, m);
> +
> +#if NBPFILTER > 0
> +             if (ifp->if_bpf)
> +                     bpf_mtap_ether(ifp->if_bpf, m, BPF_DIRECTION_OUT);
> +#endif
> +             pkts++;
> +     }
> +     if (pkts > 0) {
> +             txr->txr_prod = prod;
> +             xen_intr_signal(sc->sc_xih);
> +     }
> +}
> +
> +int
> +xnf_encap(struct xnf_softc *sc, struct mbuf *m, uint32_t *prod)
> +{
> +     struct ifnet *ifp = &sc->sc_ac.ac_if;
> +     struct xnf_tx_ring *txr = sc->sc_tx_ring;
> +     union xnf_tx_desc *txd;
> +     bus_dmamap_t dmap;
> +     int error, i, n = 0;
> +
> +     if (((txr->txr_cons - *prod - 1) & (XNF_TX_DESC - 1)) < XNF_TX_FRAG) {
> +             error = ENOENT;
> +             goto errout;
> +     }
> +
> +     i = *prod & (XNF_TX_DESC - 1);
> +     dmap = sc->sc_tx_dmap[i];
> +
> +     error = bus_dmamap_load_mbuf(sc->sc_dmat, dmap, m, BUS_DMA_WRITE |
> +         BUS_DMA_NOWAIT);
> +     if (error == EFBIG) {
> +             if (m_defrag(m, M_DONTWAIT) ||
> +                 bus_dmamap_load_mbuf(sc->sc_dmat, dmap, m, BUS_DMA_WRITE |
> +                  BUS_DMA_NOWAIT))
> +                     goto errout;
> +     } else if (error)
> +             goto errout;
> +
> +     for (n = 0; n < dmap->dm_nsegs; n++, (*prod)++) {
> +             i = *prod & (XNF_TX_DESC - 1);
> +             if (sc->sc_tx_buf[i])
> +                     panic("%s: save vs spell: %d\n", ifp->if_xname, i);
> +             txd = &txr->txr_desc[i];
> +             if (n == 0) {
> +                     sc->sc_tx_buf[i] = m;
> +                     if (0 && m->m_pkthdr.csum_flags & M_IPV4_CSUM_OUT)
> +                             txd->txd_req.txq_flags = XNF_TXF_CSUM |
> +                                 XNF_TXF_VALID;
> +                     txd->txd_req.txq_size = m->m_pkthdr.len;
> +             } else
> +                     txd->txd_req.txq_size = dmap->dm_segs[n].ds_len;
> +             if (n != dmap->dm_nsegs - 1)
> +                     txd->txd_req.txq_flags |= XNF_TXF_CHUNK;
> +             txd->txd_req.txq_ref = dmap->dm_segs[n].ds_addr;
> +             txd->txd_req.txq_offset = dmap->dm_segs[n].ds_offset;
> +     }
> +
> +     ifp->if_opackets++;
> +     return (0);
> +
> + errout:
> +     ifp->if_oerrors++;
> +     return (error);
> +}
> +
> +void
> +xnf_intr(void *arg)
> +{
> +     struct xnf_softc *sc = arg;
> +     struct ifnet *ifp = &sc->sc_ac.ac_if;
> +
> +     if (ifp->if_flags & IFF_RUNNING) {
> +             xnf_rxeof(sc);
> +             xnf_txeof(sc);
> +     }
> +}
> +
> +int
> +xnf_txeof(struct xnf_softc *sc)
> +{
> +     struct ifnet *ifp = &sc->sc_ac.ac_if;
> +     struct xnf_tx_ring *txr = sc->sc_tx_ring;
> +     union xnf_tx_desc *txd;
> +     struct mbuf *m;
> +     bus_dmamap_t dmap;
> +     volatile uint32_t r;
> +     uint32_t cons;
> +     int i, id, pkts = 0;
> +
> +     do {
> +             for (cons = sc->sc_tx_cons; cons != txr->txr_cons; cons++) {
> +                     membar_consumer();
> +                     i = cons & (XNF_TX_DESC - 1);
> +                     txd = &txr->txr_desc[i];
> +                     id = txd->txd_rsp.txp_id;
> +                     memset(txd, 0, sizeof(*txd));
> +                     txd->txd_req.txq_id = id;
> +                     membar_producer();
> +                     if (sc->sc_tx_buf[i]) {
> +                             dmap = sc->sc_tx_dmap[i];
> +                             bus_dmamap_unload(sc->sc_dmat, dmap);
> +                             m = sc->sc_tx_buf[i];
> +                             sc->sc_tx_buf[i] = NULL;
> +                             m_freem(m);
> +                     }
> +                     pkts++;
> +             }
> +
> +             if (pkts > 0) {
> +                     sc->sc_tx_cons = cons;
> +                     membar_producer();
> +                     txr->txr_rsp_evt = cons + 1;
> +                     pkts = 0;
> +             }
> +
> +             r = txr->txr_cons - sc->sc_tx_cons;
> +             membar_consumer();
> +     } while (r > 0);
> +
> +     if (ifq_is_oactive(&ifp->if_snd))
> +             ifq_restart(&ifp->if_snd);
> +
> +     return (0);
> +}

Reply via email to