On Wed, Jan 06, 2016 at 04:37:36PM +0100, 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.
> 
> OK?
> 

I can see it works now and as mentioned in icb:
I just had the first contact with OpenBSD in an EC2 instance.
(once again, we need emoji in xterm to see the U+1F596)

Two bugs:
- I didn't work on m4.10xlarge (see cvs:~reyk/dmesg.m4.10xlarge).
- One time, xnf stopped while coping a large file to a remote machine.

I think it is good enough to go in and be tweaked in the tree.

OK reyk@

> diff --git sys/arch/amd64/conf/GENERIC sys/arch/amd64/conf/GENERIC
> index fca4459..77e07cc 100644
> --- sys/arch/amd64/conf/GENERIC
> +++ sys/arch/amd64/conf/GENERIC
> @@ -67,10 +67,11 @@ mpbios0           at bios0
>  ipmi0        at mainbus? disable     # IPMI
>  
>  vmt0 at pvbus?               # VMware Tools
>  
>  #xen0        at pvbus?               # Xen HVM domU
> +#xnf*        at xen?                 # Xen Netfront
>  
>  option               PCIVERBOSE
>  option               USBVERBOSE
>  
>  pchb*        at pci?                 # PCI-Host bridges
> diff --git sys/dev/pv/files.pv sys/dev/pv/files.pv
> index d0e3b8c..e1272b2 100644
> --- sys/dev/pv/files.pv
> +++ sys/dev/pv/files.pv
> @@ -16,5 +16,9 @@ file        dev/pv/vmt.c                    vmt     
> needs-flag
>  # Xen
>  device       xen {}
>  attach       xen at pvbus
>  file dev/pv/xen.c                    xen     needs-flag
>  file dev/pv/xenstore.c               xen
> +
> +device       xnf: ether, ifnet, ifmedia
> +attach       xnf at xen
> +file dev/pv/if_xnf.c                 xnf
> diff --git sys/dev/pv/if_xnf.c sys/dev/pv/if_xnf.c
> new file mode 100644
> index 0000000..7f8b08e
> --- /dev/null
> +++ sys/dev/pv/if_xnf.c
> @@ -0,0 +1,1022 @@
> +/*
> + * Copyright (c) 2015 Mike Belopuhov
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include "bpfilter.h"
> +#include "vlan.h"
> +#include "xen.h"
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/atomic.h>
> +#include <sys/malloc.h>
> +#include <sys/mbuf.h>
> +#include <sys/kernel.h>
> +#include <sys/device.h>
> +#include <sys/socket.h>
> +#include <sys/sockio.h>
> +#include <sys/queue.h>
> +#include <sys/timeout.h>
> +#include <sys/pool.h>
> +
> +#include <machine/bus.h>
> +
> +#include <dev/pv/xenreg.h>
> +#include <dev/pv/xenvar.h>
> +
> +#include <net/if.h>
> +#include <net/if_media.h>
> +
> +#include <netinet/in.h>
> +#include <netinet/if_ether.h>
> +
> +#ifdef INET6
> +#include <netinet/ip6.h>
> +#endif
> +
> +#if NBPFILTER > 0
> +#include <net/bpf.h>
> +#endif
> +
> +
> +/*
> + * Rx ring
> + */
> +
> +struct xnf_rx_req {
> +     uint16_t                 rxq_id;
> +     uint16_t                 rxq_pad;
> +     uint32_t                 rxq_ref;
> +} __packed;
> +
> +struct xnf_rx_rsp {
> +     uint16_t                 rxp_id;
> +     uint16_t                 rxp_offset;
> +     uint16_t                 rxp_flags;
> +#define  XNF_RXF_CSUM                  0x0001
> +#define  XNF_RXF_BLANK                 0x0002
> +#define  XNF_RXF_CHUNK                 0x0004
> +#define  XNF_RXF_EXTRA                 0x0008
> +     int16_t                  rxp_status;
> +} __packed;
> +
> +union xnf_rx_desc {
> +     struct xnf_rx_req        rxd_req;
> +     struct xnf_rx_rsp        rxd_rsp;
> +} __packed;
> +
> +#define XNF_RX_DESC          256
> +#define XNF_MCLEN            PAGE_SIZE
> +#define XNF_RX_MIN           32
> +
> +struct xnf_rx_ring {
> +     uint32_t                 rxr_prod;
> +     uint32_t                 rxr_req_evt;
> +     uint32_t                 rxr_cons;
> +     uint32_t                 rxr_rsp_evt;
> +     uint32_t                 rxr_reserved[12];
> +     union xnf_rx_desc        rxr_desc[XNF_RX_DESC];
> +} __packed;
> +
> +
> +/*
> + * Tx ring
> + */
> +
> +struct xnf_tx_req {
> +     uint32_t                 txq_ref;
> +     uint16_t                 txq_offset;
> +     uint16_t                 txq_flags;
> +#define  XNF_TXF_CSUM                  0x0001
> +#define  XNF_TXF_VALID                 0x0002
> +#define  XNF_TXF_CHUNK                 0x0004
> +#define  XNF_TXF_ETXRA                 0x0008
> +     uint16_t                 txq_id;
> +     uint16_t                 txq_size;
> +} __packed;
> +
> +struct xnf_tx_rsp {
> +     uint16_t                 txp_id;
> +     int16_t                  txp_status;
> +} __packed;
> +
> +union xnf_tx_desc {
> +     struct xnf_tx_req        txd_req;
> +     struct xnf_tx_rsp        txd_rsp;
> +} __packed;
> +
> +#define XNF_TX_DESC          256
> +#define XNF_TX_FRAG          8       /* down from 18 */
> +
> +struct xnf_tx_ring {
> +     uint32_t                 txr_prod;
> +     uint32_t                 txr_req_evt;
> +     uint32_t                 txr_cons;
> +     uint32_t                 txr_rsp_evt;
> +     uint32_t                 txr_reserved[12];
> +     union xnf_tx_desc        txr_desc[XNF_TX_DESC];
> +} __packed;
> +
> +
> +/* Management frame, "extra info" in Xen parlance */
> +struct xnf_mgmt {
> +     uint8_t                  mg_type;
> +#define  XNF_MGMT_MCAST_ADD  2
> +#define  XNF_MGMT_MCAST_DEL  3
> +     uint8_t                  mg_flags;
> +     union {
> +             uint8_t          mgu_mcaddr[ETHER_ADDR_LEN];
> +             uint16_t         mgu_pad[3];
> +     } u;
> +#define mg_mcaddr             u.mgu_mcaddr
> +} __packed;
> +
> +
> +struct xnf_softc {
> +     struct device            sc_dev;
> +     struct xen_attach_args   sc_xa;
> +     struct xen_softc        *sc_xen;
> +     bus_dma_tag_t            sc_dmat;
> +
> +     struct arpcom            sc_ac;
> +     struct ifmedia           sc_media;
> +
> +     xen_intr_handle_t        sc_xih;
> +
> +     /* Rx ring */
> +     struct xnf_rx_ring      *sc_rx_ring;
> +     int                      sc_rx_cons;
> +     bus_dmamap_t             sc_rx_rmap;              /* map for the ring */
> +     bus_dma_segment_t        sc_rx_seg;
> +     uint32_t                 sc_rx_ref;               /* grant table ref */
> +     struct mbuf             *sc_rx_buf[XNF_RX_DESC];
> +     bus_dmamap_t             sc_rx_dmap[XNF_RX_DESC]; /* maps for packets */
> +     struct mbuf             *sc_rx_cbuf[2];           /* chain handling */
> +     struct if_rxring         sc_rx_slots;
> +     struct timeout           sc_rx_fill;
> +
> +     /* Tx ring */
> +     struct xnf_tx_ring      *sc_tx_ring;
> +     int                      sc_tx_cons;
> +     bus_dmamap_t             sc_tx_rmap;              /* map for the ring */
> +     bus_dma_segment_t        sc_tx_seg;
> +     uint32_t                 sc_tx_ref;               /* grant table ref */
> +     struct mbuf             *sc_tx_buf[XNF_TX_DESC];
> +     bus_dmamap_t             sc_tx_dmap[XNF_TX_DESC]; /* maps for packets */
> +};
> +
> +int  xnf_match(struct device *, void *, void *);
> +void xnf_attach(struct device *, struct device *, void *);
> +int  xnf_lladdr(struct xnf_softc *);
> +int  xnf_ioctl(struct ifnet *, u_long, caddr_t);
> +int  xnf_media_change(struct ifnet *);
> +void xnf_media_status(struct ifnet *, struct ifmediareq *);
> +int  xnf_iff(struct xnf_softc *);
> +void xnf_init(struct xnf_softc *);
> +void xnf_stop(struct xnf_softc *);
> +void xnf_start(struct ifnet *);
> +int  xnf_encap(struct xnf_softc *, struct mbuf *, uint32_t *);
> +void xnf_intr(void *);
> +int  xnf_txeof(struct xnf_softc *);
> +int  xnf_rxeof(struct xnf_softc *);
> +void xnf_rx_ring_fill(void *);
> +int  xnf_rx_ring_create(struct xnf_softc *);
> +void xnf_rx_ring_drain(struct xnf_softc *);
> +void xnf_rx_ring_destroy(struct xnf_softc *);
> +int  xnf_tx_ring_create(struct xnf_softc *);
> +void xnf_tx_ring_drain(struct xnf_softc *);
> +void xnf_tx_ring_destroy(struct xnf_softc *);
> +int  xnf_init_backend(struct xnf_softc *);
> +int  xnf_stop_backend(struct xnf_softc *);
> +
> +struct cfdriver xnf_cd = {
> +     NULL, "xnf", DV_IFNET
> +};
> +
> +const struct cfattach xnf_ca = {
> +     sizeof(struct xnf_softc), xnf_match, xnf_attach
> +};
> +
> +int
> +xnf_match(struct device *parent, void *match, void *aux)
> +{
> +     struct xen_attach_args *xa = aux;
> +     char type[64];
> +
> +     if (strcmp("vif", xa->xa_name))
> +             return (0);
> +
> +     if (xs_getprop(xa, "type", type, sizeof(type)) == 0 &&
> +         ((strcmp("vif", type) == 0) || (strcmp("front", type) == 0)))
> +             return (1);
> +
> +     return (0);
> +}
> +
> +void
> +xnf_attach(struct device *parent, struct device *self, void *aux)
> +{
> +     struct xen_attach_args *xa = aux;
> +     struct xnf_softc *sc = (struct xnf_softc *)self;
> +     struct ifnet *ifp = &sc->sc_ac.ac_if;
> +
> +     sc->sc_xa = *xa;
> +     sc->sc_xen = xa->xa_parent;
> +     sc->sc_dmat = xa->xa_dmat;
> +
> +     strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
> +
> +     if (xnf_lladdr(sc)) {
> +             printf(": failed to obtain MAC address\n");
> +             return;
> +     }
> +
> +     if (xen_intr_establish(0, &sc->sc_xih, xnf_intr, sc, ifp->if_xname)) {
> +             printf("%s: failed to establish an interrupt\n", ifp->if_xname);
> +             return;
> +     }
> +
> +     printf(": event channel %u, address %s\n", sc->sc_xih,
> +         ether_sprintf(sc->sc_ac.ac_enaddr));
> +
> +     if (xnf_rx_ring_create(sc)) {
> +             xen_intr_disestablish(sc->sc_xih);
> +             return;
> +     }
> +     if (xnf_tx_ring_create(sc)) {
> +             xen_intr_disestablish(sc->sc_xih);
> +             xnf_rx_ring_destroy(sc);
> +             return;
> +     }
> +     if (xnf_init_backend(sc)) {
> +             xen_intr_disestablish(sc->sc_xih);
> +             xnf_rx_ring_destroy(sc);
> +             xnf_tx_ring_destroy(sc);
> +             return;
> +     }
> +
> +     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
> +     ifp->if_xflags = IFXF_MPSAFE;
> +     ifp->if_ioctl = xnf_ioctl;
> +     ifp->if_start = xnf_start;
> +     ifp->if_softc = sc;
> +
> +     ifp->if_capabilities = IFCAP_VLAN_MTU;
> +
> +     IFQ_SET_MAXLEN(&ifp->if_snd, XNF_TX_DESC - 1);
> +     IFQ_SET_READY(&ifp->if_snd);
> +
> +     ifmedia_init(&sc->sc_media, IFM_IMASK, xnf_media_change,
> +         xnf_media_status);
> +     ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
> +     ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
> +
> +     if_attach(ifp);
> +     ether_ifattach(ifp);
> +
> +     timeout_set(&sc->sc_rx_fill, xnf_rx_ring_fill, sc);
> +}
> +
> +static int
> +nibble(int ch)
> +{
> +     if (ch >= '0' && ch <= '9')
> +             return (ch - '0');
> +     if (ch >= 'A' && ch <= 'F')
> +             return (10 + ch - 'A');
> +     if (ch >= 'a' && ch <= 'f')
> +             return (10 + ch - 'a');
> +     return (-1);
> +}
> +
> +int
> +xnf_lladdr(struct xnf_softc *sc)
> +{
> +     char enaddr[ETHER_ADDR_LEN];
> +     char mac[32];
> +     int i, j, lo, hi;
> +
> +     if (xs_getprop(&sc->sc_xa, "mac", mac, sizeof(mac)))
> +             return (-1);
> +
> +     for (i = 0, j = 0; j < ETHER_ADDR_LEN; i += 3) {
> +             if ((hi = nibble(mac[i])) == -1 ||
> +                 (lo = nibble(mac[i+1])) == -1)
> +                     return (-1);
> +             enaddr[j++] = hi << 4 | lo;
> +     }
> +
> +     memcpy(sc->sc_ac.ac_enaddr, enaddr, ETHER_ADDR_LEN);
> +     return (0);
> +}
> +
> +int
> +xnf_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
> +{
> +     struct xnf_softc *sc = ifp->if_softc;
> +     struct ifreq *ifr = (struct ifreq *)data;
> +     int s, error = 0;
> +
> +     s = splnet();
> +
> +     switch (command) {
> +     case SIOCSIFADDR:
> +             ifp->if_flags |= IFF_UP;
> +             if (!(ifp->if_flags & IFF_RUNNING))
> +                     xnf_init(sc);
> +             break;
> +     case SIOCSIFFLAGS:
> +             if (ifp->if_flags & IFF_UP) {
> +                     if (ifp->if_flags & IFF_RUNNING)
> +                             error = ENETRESET;
> +                     else
> +                             xnf_init(sc);
> +             } else {
> +                     if (ifp->if_flags & IFF_RUNNING)
> +                             xnf_stop(sc);
> +             }
> +             break;
> +     case SIOCGIFMEDIA:
> +     case SIOCSIFMEDIA:
> +             error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, command);
> +             break;
> +     case SIOCGIFRXR:
> +             error = if_rxr_ioctl((struct if_rxrinfo *)ifr->ifr_data,
> +                 NULL, XNF_MCLEN, &sc->sc_rx_slots);
> +             break;
> +     default:
> +             error = ether_ioctl(ifp, &sc->sc_ac, command, data);
> +             break;
> +     }
> +
> +     if (error == ENETRESET) {
> +             if (ifp->if_flags & IFF_RUNNING)
> +                     xnf_iff(sc);
> +             error = 0;
> +     }
> +
> +     splx(s);
> +
> +     return (error);
> +}
> +
> +int
> +xnf_media_change(struct ifnet *ifp)
> +{
> +     return (0);
> +}
> +
> +void
> +xnf_media_status(struct ifnet *ifp, struct ifmediareq *ifmr)
> +{
> +     ifmr->ifm_status = IFM_ACTIVE | IFM_AVALID;
> +     ifmr->ifm_active = IFM_ETHER | IFM_MANUAL;
> +}
> +
> +int
> +xnf_iff(struct xnf_softc *sc)
> +{
> +     return (0);
> +}
> +
> +void
> +xnf_init(struct xnf_softc *sc)
> +{
> +     struct ifnet *ifp = &sc->sc_ac.ac_if;
> +
> +     xnf_stop(sc);
> +
> +     xnf_iff(sc);
> +
> +     if (xen_intr_unmask(sc->sc_xih)) {
> +             printf("%s: failed to enable interrupts\n", ifp->if_xname);
> +             xnf_stop(sc);
> +             return;
> +     }
> +
> +     ifp->if_flags |= IFF_RUNNING;
> +     ifq_clr_oactive(&ifp->if_snd);
> +}
> +
> +void
> +xnf_stop(struct xnf_softc *sc)
> +{
> +     struct ifnet *ifp = &sc->sc_ac.ac_if;
> +
> +     ifp->if_flags &= ~IFF_RUNNING;
> +
> +     xen_intr_mask(sc->sc_xih);
> +
> +     timeout_del(&sc->sc_rx_fill);
> +
> +     ifq_barrier(&ifp->if_snd);
> +     intr_barrier(&sc->sc_xih);
> +
> +     ifq_clr_oactive(&ifp->if_snd);
> +
> +     if (sc->sc_tx_ring)
> +             xnf_tx_ring_drain(sc);
> +     if (sc->sc_rx_ring)
> +             xnf_rx_ring_drain(sc);
> +}
> +
> +void
> +xnf_start(struct ifnet *ifp)
> +{
> +     struct xnf_softc *sc = ifp->if_softc;
> +     struct xnf_tx_ring *txr = sc->sc_tx_ring;
> +     struct mbuf *m;
> +     int error, pkts = 0;
> +     uint32_t prod;
> +
> +     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);
> +}
> +
> +int
> +xnf_rxeof(struct xnf_softc *sc)
> +{
> +     struct ifnet *ifp = &sc->sc_ac.ac_if;
> +     struct xnf_rx_ring *rxr = sc->sc_rx_ring;
> +     union xnf_rx_desc *rxd;
> +     struct mbuf_list ml = MBUF_LIST_INITIALIZER();
> +     struct mbuf *fmp = sc->sc_rx_cbuf[0];
> +     struct mbuf *lmp = sc->sc_rx_cbuf[1];
> +     struct mbuf *m;
> +     bus_dmamap_t dmap;
> +     volatile uint32_t r;
> +     uint32_t cons;
> +     int i, id, flags, len, offset, pkts = 0;
> +
> +     do {
> +             for (cons = sc->sc_rx_cons; cons != rxr->rxr_cons; cons++) {
> +                     membar_consumer();
> +                     i = cons & (XNF_RX_DESC - 1);
> +                     rxd = &rxr->rxr_desc[i];
> +                     dmap = sc->sc_rx_dmap[i];
> +
> +                     len = rxd->rxd_rsp.rxp_status;
> +                     flags = rxd->rxd_rsp.rxp_flags;
> +                     offset = rxd->rxd_rsp.rxp_offset;
> +                     id = rxd->rxd_rsp.rxp_id;
> +                     memset(rxd, 0, sizeof(*rxd));
> +                     rxd->rxd_req.rxq_id = id;
> +                     membar_producer();
> +
> +                     bus_dmamap_unload(sc->sc_dmat, dmap);
> +
> +                     m = sc->sc_rx_buf[i];
> +                     KASSERT(m != NULL);
> +                     sc->sc_rx_buf[i] = NULL;
> +
> +                     if (flags & XNF_RXF_EXTRA)
> +                             printf("%s: management data present\n",
> +                                 ifp->if_xname);
> +
> +                     if (flags & XNF_RXF_CSUM)
> +                             m->m_pkthdr.csum_flags = M_IPV4_CSUM_IN_OK;
> +
> +                     if_rxr_put(&sc->sc_rx_slots, 1);
> +                     pkts++;
> +
> +                     if (len < 0 || (len + offset > PAGE_SIZE)) {
> +                             ifp->if_ierrors++;
> +                             m_freem(m);
> +                             continue;
> +                     }
> +
> +                     m->m_len = len;
> +                     m->m_data += offset;
> +
> +                     if (fmp == NULL) {
> +                             m->m_pkthdr.len = len;
> +                             fmp = m;
> +                     } else {
> +                             m->m_flags &= ~M_PKTHDR;
> +                             lmp->m_next = m;
> +                             fmp->m_pkthdr.len += m->m_len;
> +                     }
> +                     lmp = m;
> +
> +                     if (flags & XNF_RXF_CHUNK) {
> +                             sc->sc_rx_cbuf[0] = fmp;
> +                             sc->sc_rx_cbuf[1] = lmp;
> +                             continue;
> +                     }
> +
> +                     m = fmp;
> +
> +                     ml_enqueue(&ml, m);
> +                     sc->sc_rx_cbuf[0] = sc->sc_rx_cbuf[1] =
> +                         fmp = lmp = NULL;
> +             }
> +
> +             if (pkts > 0) {
> +                     sc->sc_rx_cons = cons;
> +                     membar_producer();
> +                     rxr->rxr_rsp_evt = cons + 1;
> +                     pkts = 0;
> +             }
> +
> +             r = rxr->rxr_cons - sc->sc_rx_cons;
> +             membar_consumer();
> +     } while (r > 0);
> +
> +     if (!ml_empty(&ml)) {
> +             if_input(ifp, &ml);
> +
> +             xnf_rx_ring_fill(sc);
> +     }
> +
> +     return (0);
> +}
> +
> +void
> +xnf_rx_ring_fill(void *arg)
> +{
> +     struct xnf_softc *sc = arg;
> +     struct ifnet *ifp = &sc->sc_ac.ac_if;
> +     struct xnf_rx_ring *rxr = sc->sc_rx_ring;
> +     bus_dmamap_t dmap;
> +     struct mbuf *m;
> +     uint32_t cons, prod;
> +     static int timer = 0;
> +     int i, n;
> +
> +     cons = rxr->rxr_cons;
> +     prod = rxr->rxr_prod;
> +
> +     n = if_rxr_get(&sc->sc_rx_slots, XNF_RX_DESC);
> +
> +     /* Less than XNF_RX_MIN slots available? */
> +     if (n == 0 && prod - cons < XNF_RX_MIN) {
> +             if (ifp->if_flags & IFF_RUNNING)
> +                     timeout_add(&sc->sc_rx_fill, 1 << timer);
> +             if (timer < 10)
> +                     timer++;
> +             return;
> +     }
> +
> +     for (; n > 0; prod++, n--) {
> +             i = prod & (XNF_RX_DESC - 1);
> +             if (sc->sc_rx_buf[i])
> +                     break;
> +             m = MCLGETI(NULL, M_DONTWAIT, NULL, XNF_MCLEN);
> +             if (m == NULL)
> +                     break;
> +             m->m_len = m->m_pkthdr.len = XNF_MCLEN;
> +             dmap = sc->sc_rx_dmap[i];
> +             if (bus_dmamap_load_mbuf(sc->sc_dmat, dmap, m, BUS_DMA_READ |
> +                 BUS_DMA_NOWAIT)) {
> +                     m_freem(m);
> +                     break;
> +             }
> +             sc->sc_rx_buf[i] = m;
> +             rxr->rxr_desc[i].rxd_req.rxq_ref = dmap->dm_segs[0].ds_addr;
> +     }
> +
> +     if (n > 0)
> +             if_rxr_put(&sc->sc_rx_slots, n);
> +
> +     membar_producer();
> +     rxr->rxr_prod = prod;
> +
> +     xen_intr_signal(sc->sc_xih);
> +}
> +
> +int
> +xnf_rx_ring_create(struct xnf_softc *sc)
> +{
> +     int i, rsegs;
> +
> +     /* Allocate a page of memory for the ring */
> +     if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
> +         &sc->sc_rx_seg, 1, &rsegs, BUS_DMA_ZERO | BUS_DMA_WAITOK)) {
> +             printf("%s: failed to allocate memory for the rx ring\n",
> +                 sc->sc_dev.dv_xname);
> +             return (-1);
> +     }
> +     /* Map in the allocated memory into the ring structure */
> +     if (bus_dmamem_map(sc->sc_dmat, &sc->sc_rx_seg, 1, PAGE_SIZE,
> +         (caddr_t *)(&sc->sc_rx_ring), BUS_DMA_WAITOK)) {
> +             printf("%s: failed to map memory for the rx ring\n",
> +                 sc->sc_dev.dv_xname);
> +             goto errout;
> +     }
> +     /* Create a map to load the ring memory into */
> +     if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
> +         BUS_DMA_WAITOK, &sc->sc_rx_rmap)) {
> +             printf("%s: failed to create a memory map for the rx ring\n",
> +                 sc->sc_dev.dv_xname);
> +             goto errout;
> +     }
> +     /* Load the ring into the ring map to extract the PA */
> +     if (bus_dmamap_load(sc->sc_dmat, sc->sc_rx_rmap, sc->sc_rx_ring,
> +         PAGE_SIZE, NULL, BUS_DMA_WAITOK)) {
> +             printf("%s: failed to load the rx ring map\n",
> +                 sc->sc_dev.dv_xname);
> +             goto errout;
> +     }
> +     sc->sc_rx_ref = sc->sc_rx_rmap->dm_segs[0].ds_addr;
> +
> +     sc->sc_rx_ring->rxr_req_evt = sc->sc_rx_ring->rxr_rsp_evt = 1;
> +
> +     for (i = 0; i < XNF_RX_DESC; i++) {
> +             if (bus_dmamap_create(sc->sc_dmat, XNF_MCLEN, 1,
> +                 XNF_MCLEN, 0, BUS_DMA_WAITOK, &sc->sc_rx_dmap[i])) {
> +                     printf("%s: failed to create a memory map for the rx "
> +                         "slot %d/%d\n", sc->sc_dev.dv_xname, i,
> +                         XNF_RX_DESC);
> +                     goto errout;
> +             }
> +             sc->sc_rx_ring->rxr_desc[i].rxd_req.rxq_id = i;
> +     }
> +
> +     if_rxr_init(&sc->sc_rx_slots, XNF_RX_MIN, XNF_RX_DESC);
> +     xnf_rx_ring_fill(sc);
> +
> +     return (0);
> +
> + errout:
> +     xnf_rx_ring_destroy(sc);
> +     return (-1);
> +}
> +
> +void
> +xnf_rx_ring_drain(struct xnf_softc *sc)
> +{
> +     struct xnf_rx_ring *rxr = sc->sc_rx_ring;
> +
> +     if (sc->sc_rx_cons != rxr->rxr_cons)
> +             xnf_rxeof(sc);
> +}
> +
> +void
> +xnf_rx_ring_destroy(struct xnf_softc *sc)
> +{
> +     int i, slots = 0;
> +
> +     for (i = 0; i < XNF_RX_DESC; i++) {
> +             if (sc->sc_rx_buf[i] == NULL)
> +                     continue;
> +             bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_dmap[i]);
> +             m_freem(sc->sc_rx_buf[i]);
> +             sc->sc_rx_buf[i] = NULL;
> +             slots++;
> +     }
> +     printf("%s: unload done\n", __func__);
> +     if_rxr_put(&sc->sc_rx_slots, slots);
> +     printf("%s: rxr_put done\n", __func__);
> +
> +     for (i = 0; i < XNF_RX_DESC; i++) {
> +             if (sc->sc_rx_dmap[i] == NULL)
> +                     continue;
> +             bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_dmap[i]);
> +             sc->sc_rx_dmap[i] = NULL;
> +     }
> +     printf("%s: desc map destroy done\n", __func__);
> +     if (sc->sc_rx_rmap) {
> +             bus_dmamap_unload(sc->sc_dmat, sc->sc_rx_rmap);
> +             bus_dmamap_destroy(sc->sc_dmat, sc->sc_rx_rmap);
> +     }
> +     printf("%s: ring map destroy done\n", __func__);
> +     if (sc->sc_rx_ring) {
> +             bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_rx_ring,
> +                 PAGE_SIZE);
> +             bus_dmamem_free(sc->sc_dmat, &sc->sc_rx_seg, 1);
> +     }
> +     printf("%s: ring mem free done\n", __func__);
> +     sc->sc_rx_ring = NULL;
> +     sc->sc_rx_rmap = NULL;
> +     sc->sc_rx_cons = 0;
> +}
> +
> +int
> +xnf_tx_ring_create(struct xnf_softc *sc)
> +{
> +     int i, rsegs;
> +
> +     /* Allocate a page of memory for the ring */
> +     if (bus_dmamem_alloc(sc->sc_dmat, PAGE_SIZE, PAGE_SIZE, 0,
> +         &sc->sc_tx_seg, 1, &rsegs, BUS_DMA_ZERO | BUS_DMA_WAITOK)) {
> +             printf("%s: failed to allocate memory for the tx ring\n",
> +                 sc->sc_dev.dv_xname);
> +             return (-1);
> +     }
> +     /* Map in the allocated memory into the ring structure */
> +     if (bus_dmamem_map(sc->sc_dmat, &sc->sc_tx_seg, 1, PAGE_SIZE,
> +         (caddr_t *)&sc->sc_tx_ring, BUS_DMA_WAITOK)) {
> +             printf("%s: failed to map memory for the tx ring\n",
> +                 sc->sc_dev.dv_xname);
> +             goto errout;
> +     }
> +     /* Create a map to load the ring memory into */
> +     if (bus_dmamap_create(sc->sc_dmat, PAGE_SIZE, 1, PAGE_SIZE, 0,
> +         BUS_DMA_WAITOK, &sc->sc_tx_rmap)) {
> +             printf("%s: failed to create a memory map for the tx ring\n",
> +                 sc->sc_dev.dv_xname);
> +             goto errout;
> +     }
> +     /* Load the ring into the ring map to extract the PA */
> +     if (bus_dmamap_load(sc->sc_dmat, sc->sc_tx_rmap, sc->sc_tx_ring,
> +         PAGE_SIZE, NULL, BUS_DMA_WAITOK)) {
> +             printf("%s: failed to load the tx ring map\n",
> +                 sc->sc_dev.dv_xname);
> +             goto errout;
> +     }
> +     sc->sc_tx_ref = sc->sc_tx_rmap->dm_segs[0].ds_addr;
> +
> +     sc->sc_tx_ring->txr_req_evt = sc->sc_tx_ring->txr_rsp_evt = 1;
> +
> +     for (i = 0; i < XNF_TX_DESC; i++) {
> +             if (bus_dmamap_create(sc->sc_dmat, XNF_MCLEN, XNF_TX_FRAG,
> +                 XNF_MCLEN, 0, BUS_DMA_WAITOK, &sc->sc_tx_dmap[i])) {
> +                     printf("%s: failed to create a memory map for the tx "
> +                         "slot %d/%d\n", sc->sc_dev.dv_xname, i,
> +                         XNF_TX_DESC);
> +                     goto errout;
> +             }
> +             sc->sc_tx_ring->txr_desc[i].txd_req.txq_id = i;
> +     }
> +
> +     return (0);
> +
> + errout:
> +     xnf_tx_ring_destroy(sc);
> +     return (-1);
> +}
> +
> +void
> +xnf_tx_ring_drain(struct xnf_softc *sc)
> +{
> +     struct xnf_tx_ring *txr = sc->sc_tx_ring;
> +
> +     if (sc->sc_tx_cons != txr->txr_cons)
> +             xnf_txeof(sc);
> +}
> +
> +void
> +xnf_tx_ring_destroy(struct xnf_softc *sc)
> +{
> +     int i;
> +
> +     for (i = 0; i < XNF_TX_DESC; i++) {
> +             if (sc->sc_tx_dmap[i] == NULL)
> +                     continue;
> +             bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_dmap[i]);
> +             if (sc->sc_tx_buf[i] == NULL)
> +                     continue;
> +             m_freem(sc->sc_tx_buf[i]);
> +             sc->sc_tx_buf[i] = NULL;
> +     }
> +     for (i = 0; i < XNF_TX_DESC; i++) {
> +             if (sc->sc_tx_dmap[i] == NULL)
> +                     continue;
> +             bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_dmap[i]);
> +             sc->sc_tx_dmap[i] = NULL;
> +     }
> +     if (sc->sc_tx_rmap) {
> +             bus_dmamap_unload(sc->sc_dmat, sc->sc_tx_rmap);
> +             bus_dmamap_destroy(sc->sc_dmat, sc->sc_tx_rmap);
> +     }
> +     if (sc->sc_tx_ring) {
> +             bus_dmamem_unmap(sc->sc_dmat, (caddr_t)sc->sc_tx_ring,
> +                 PAGE_SIZE);
> +             bus_dmamem_free(sc->sc_dmat, &sc->sc_tx_seg, 1);
> +     }
> +     sc->sc_tx_ring = NULL;
> +     sc->sc_tx_rmap = NULL;
> +}
> +
> +int
> +xnf_init_backend(struct xnf_softc *sc)
> +{
> +     const char *prop;
> +     char val[32];
> +
> +     /* Plumb the Rx ring */
> +     prop = "rx-ring-ref";
> +     snprintf(val, sizeof(val), "%u", sc->sc_rx_ref);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +     /* Enable "copy" mode */
> +     prop = "request-rx-copy";
> +     snprintf(val, sizeof(val), "%u", 1);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +     /* Enable notify mode */
> +     prop = "feature-rx-notify";
> +     snprintf(val, sizeof(val), "%u", 1);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +     /* Request multicast filtering */
> +     prop = "request-multicast-control";
> +     snprintf(val, sizeof(val), "%u", 1);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +
> +     /* Plumb the Tx ring */
> +     prop = "tx-ring-ref";
> +     snprintf(val, sizeof(val), "%u", sc->sc_tx_ref);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +     /* Enable transmit scatter-gather mode */
> +     prop = "feature-sg";
> +     snprintf(val, sizeof(val), "%u", 1);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +
> +     /* Disable TCP/UDP checksum offload */
> +     prop = "feature-csum-offload";
> +     if (xs_setprop(&sc->sc_xa, prop, NULL, 0))
> +             goto errout;
> +     prop = "feature-no-csum-offload";
> +     snprintf(val, sizeof(val), "%u", 1);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +     prop = "feature-ipv6-csum-offload";
> +     if (xs_setprop(&sc->sc_xa, prop, NULL, 0))
> +             goto errout;
> +     prop = "feature-no-ipv6-csum-offload";
> +     snprintf(val, sizeof(val), "%u", 1);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +
> +     /* Plumb the event channel port */
> +     prop = "event-channel";
> +     snprintf(val, sizeof(val), "%u", sc->sc_xih);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +
> +     /* Connect the device */
> +     prop = "state";
> +     snprintf(val, sizeof(val), "%u", 4);
> +     if (xs_setprop(&sc->sc_xa, prop, val, strlen(val)))
> +             goto errout;
> +
> +     return (0);
> +
> + errout:
> +     printf("%s: failed to set \"%s\" property to \"%s\"\n",
> +         sc->sc_dev.dv_xname, prop, val);
> +     return (-1);
> +}
> 

-- 

Reply via email to