[BACK]Return to if_vioif.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / dev / pci

Annotation of src/sys/dev/pci/if_vioif.c, Revision 1.39.2.1

1.39.2.1! pgoyette    1: /*     $NetBSD: if_vioif.c,v 1.40 2018/06/10 14:59:23 jakllsch Exp $   */
1.1       hannken     2:
                      3: /*
                      4:  * Copyright (c) 2010 Minoura Makoto.
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
                     17:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     18:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     19:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
                     20:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     21:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
                     22:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
                     23:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
                     24:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
                     25:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     26:  */
                     27:
                     28: #include <sys/cdefs.h>
1.39.2.1! pgoyette   29: __KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.40 2018/06/10 14:59:23 jakllsch Exp $");
1.15      ozaki-r    30:
                     31: #ifdef _KERNEL_OPT
                     32: #include "opt_net_mpsafe.h"
                     33: #endif
1.1       hannken    34:
                     35: #include <sys/param.h>
                     36: #include <sys/systm.h>
                     37: #include <sys/kernel.h>
                     38: #include <sys/bus.h>
                     39: #include <sys/condvar.h>
                     40: #include <sys/device.h>
                     41: #include <sys/intr.h>
                     42: #include <sys/kmem.h>
                     43: #include <sys/mbuf.h>
                     44: #include <sys/mutex.h>
                     45: #include <sys/sockio.h>
1.12      ozaki-r    46: #include <sys/cpu.h>
1.26      pgoyette   47: #include <sys/module.h>
1.1       hannken    48:
                     49: #include <dev/pci/virtioreg.h>
                     50: #include <dev/pci/virtiovar.h>
                     51:
                     52: #include <net/if.h>
                     53: #include <net/if_media.h>
                     54: #include <net/if_ether.h>
                     55:
                     56: #include <net/bpf.h>
                     57:
1.26      pgoyette   58: #include "ioconf.h"
1.1       hannken    59:
1.7       ozaki-r    60: #ifdef NET_MPSAFE
                     61: #define VIOIF_MPSAFE   1
                     62: #endif
                     63:
1.12      ozaki-r    64: #ifdef SOFTINT_INTR
                     65: #define VIOIF_SOFTINT_INTR     1
                     66: #endif
                     67:
1.1       hannken    68: /*
                     69:  * if_vioifreg.h:
                     70:  */
                     71: /* Configuration registers */
                     72: #define VIRTIO_NET_CONFIG_MAC          0 /* 8bit x 6byte */
                     73: #define VIRTIO_NET_CONFIG_STATUS       6 /* 16bit */
                     74:
                     75: /* Feature bits */
                     76: #define VIRTIO_NET_F_CSUM      (1<<0)
                     77: #define VIRTIO_NET_F_GUEST_CSUM        (1<<1)
                     78: #define VIRTIO_NET_F_MAC       (1<<5)
                     79: #define VIRTIO_NET_F_GSO       (1<<6)
                     80: #define VIRTIO_NET_F_GUEST_TSO4        (1<<7)
                     81: #define VIRTIO_NET_F_GUEST_TSO6        (1<<8)
                     82: #define VIRTIO_NET_F_GUEST_ECN (1<<9)
                     83: #define VIRTIO_NET_F_GUEST_UFO (1<<10)
                     84: #define VIRTIO_NET_F_HOST_TSO4 (1<<11)
                     85: #define VIRTIO_NET_F_HOST_TSO6 (1<<12)
                     86: #define VIRTIO_NET_F_HOST_ECN  (1<<13)
                     87: #define VIRTIO_NET_F_HOST_UFO  (1<<14)
                     88: #define VIRTIO_NET_F_MRG_RXBUF (1<<15)
                     89: #define VIRTIO_NET_F_STATUS    (1<<16)
                     90: #define VIRTIO_NET_F_CTRL_VQ   (1<<17)
                     91: #define VIRTIO_NET_F_CTRL_RX   (1<<18)
                     92: #define VIRTIO_NET_F_CTRL_VLAN (1<<19)
                     93:
1.18      christos   94: #define VIRTIO_NET_FLAG_BITS \
                     95:        VIRTIO_COMMON_FLAG_BITS \
                     96:        "\x14""CTRL_VLAN" \
                     97:        "\x13""CTRL_RX" \
                     98:        "\x12""CTRL_VQ" \
                     99:        "\x11""STATUS" \
                    100:        "\x10""MRG_RXBUF" \
                    101:        "\x0f""HOST_UFO" \
                    102:        "\x0e""HOST_ECN" \
                    103:        "\x0d""HOST_TSO6" \
                    104:        "\x0c""HOST_TSO4" \
                    105:        "\x0b""GUEST_UFO" \
                    106:        "\x0a""GUEST_ECN" \
                    107:        "\x09""GUEST_TSO6" \
                    108:        "\x08""GUEST_TSO4" \
                    109:        "\x07""GSO" \
                    110:        "\x06""MAC" \
                    111:        "\x02""GUEST_CSUM" \
                    112:        "\x01""CSUM"
                    113:
1.1       hannken   114: /* Status */
                    115: #define VIRTIO_NET_S_LINK_UP   1
                    116:
                    117: /* Packet header structure */
                    118: struct virtio_net_hdr {
                    119:        uint8_t         flags;
                    120:        uint8_t         gso_type;
                    121:        uint16_t        hdr_len;
                    122:        uint16_t        gso_size;
                    123:        uint16_t        csum_start;
                    124:        uint16_t        csum_offset;
                    125: #if 0
                    126:        uint16_t        num_buffers; /* if VIRTIO_NET_F_MRG_RXBUF enabled */
                    127: #endif
                    128: } __packed;
                    129:
                    130: #define VIRTIO_NET_HDR_F_NEEDS_CSUM    1 /* flags */
                    131: #define VIRTIO_NET_HDR_GSO_NONE                0 /* gso_type */
                    132: #define VIRTIO_NET_HDR_GSO_TCPV4       1 /* gso_type */
                    133: #define VIRTIO_NET_HDR_GSO_UDP         3 /* gso_type */
                    134: #define VIRTIO_NET_HDR_GSO_TCPV6       4 /* gso_type */
                    135: #define VIRTIO_NET_HDR_GSO_ECN         0x80 /* gso_type, |'ed */
                    136:
                    137: #define VIRTIO_NET_MAX_GSO_LEN         (65536+ETHER_HDR_LEN)
                    138:
                    139: /* Control virtqueue */
                    140: struct virtio_net_ctrl_cmd {
                    141:        uint8_t class;
                    142:        uint8_t command;
                    143: } __packed;
                    144: #define VIRTIO_NET_CTRL_RX             0
                    145: # define VIRTIO_NET_CTRL_RX_PROMISC    0
                    146: # define VIRTIO_NET_CTRL_RX_ALLMULTI   1
                    147:
                    148: #define VIRTIO_NET_CTRL_MAC            1
                    149: # define VIRTIO_NET_CTRL_MAC_TABLE_SET 0
                    150:
                    151: #define VIRTIO_NET_CTRL_VLAN           2
                    152: # define VIRTIO_NET_CTRL_VLAN_ADD      0
                    153: # define VIRTIO_NET_CTRL_VLAN_DEL      1
                    154:
                    155: struct virtio_net_ctrl_status {
                    156:        uint8_t ack;
                    157: } __packed;
                    158: #define VIRTIO_NET_OK                  0
                    159: #define VIRTIO_NET_ERR                 1
                    160:
                    161: struct virtio_net_ctrl_rx {
                    162:        uint8_t onoff;
                    163: } __packed;
                    164:
                    165: struct virtio_net_ctrl_mac_tbl {
                    166:        uint32_t nentries;
                    167:        uint8_t macs[][ETHER_ADDR_LEN];
                    168: } __packed;
                    169:
                    170: struct virtio_net_ctrl_vlan {
                    171:        uint16_t id;
                    172: } __packed;
                    173:
                    174:
                    175: /*
                    176:  * if_vioifvar.h:
                    177:  */
                    178: struct vioif_softc {
                    179:        device_t                sc_dev;
                    180:
                    181:        struct virtio_softc     *sc_virtio;
                    182:        struct virtqueue        sc_vq[3];
1.19      ozaki-r   183: #define VQ_RX  0
                    184: #define VQ_TX  1
                    185: #define VQ_CTRL        2
1.1       hannken   186:
                    187:        uint8_t                 sc_mac[ETHER_ADDR_LEN];
                    188:        struct ethercom         sc_ethercom;
1.8       pooka     189:        short                   sc_deferred_init_done;
1.34      ozaki-r   190:        bool                    sc_link_active;
1.1       hannken   191:
                    192:        /* bus_dmamem */
                    193:        bus_dma_segment_t       sc_hdr_segs[1];
                    194:        struct virtio_net_hdr   *sc_hdrs;
                    195: #define sc_rx_hdrs     sc_hdrs
                    196:        struct virtio_net_hdr   *sc_tx_hdrs;
                    197:        struct virtio_net_ctrl_cmd *sc_ctrl_cmd;
                    198:        struct virtio_net_ctrl_status *sc_ctrl_status;
                    199:        struct virtio_net_ctrl_rx *sc_ctrl_rx;
                    200:        struct virtio_net_ctrl_mac_tbl *sc_ctrl_mac_tbl_uc;
                    201:        struct virtio_net_ctrl_mac_tbl *sc_ctrl_mac_tbl_mc;
                    202:
                    203:        /* kmem */
                    204:        bus_dmamap_t            *sc_arrays;
                    205: #define sc_rxhdr_dmamaps sc_arrays
                    206:        bus_dmamap_t            *sc_txhdr_dmamaps;
                    207:        bus_dmamap_t            *sc_rx_dmamaps;
                    208:        bus_dmamap_t            *sc_tx_dmamaps;
                    209:        struct mbuf             **sc_rx_mbufs;
                    210:        struct mbuf             **sc_tx_mbufs;
                    211:
                    212:        bus_dmamap_t            sc_ctrl_cmd_dmamap;
                    213:        bus_dmamap_t            sc_ctrl_status_dmamap;
                    214:        bus_dmamap_t            sc_ctrl_rx_dmamap;
                    215:        bus_dmamap_t            sc_ctrl_tbl_uc_dmamap;
                    216:        bus_dmamap_t            sc_ctrl_tbl_mc_dmamap;
                    217:
                    218:        void                    *sc_rx_softint;
1.34      ozaki-r   219:        void                    *sc_ctl_softint;
1.1       hannken   220:
                    221:        enum {
                    222:                FREE, INUSE, DONE
                    223:        }                       sc_ctrl_inuse;
                    224:        kcondvar_t              sc_ctrl_wait;
                    225:        kmutex_t                sc_ctrl_wait_lock;
1.36      jdolecek  226:        kmutex_t                sc_tx_lock;
                    227:        kmutex_t                sc_rx_lock;
1.7       ozaki-r   228:        bool                    sc_stopping;
1.32      jdolecek  229:
                    230:        bool                    sc_has_ctrl;
1.1       hannken   231: };
                    232: #define VIRTIO_NET_TX_MAXNSEGS         (16) /* XXX */
                    233: #define VIRTIO_NET_CTRL_MAC_MAXENTRIES (64) /* XXX */
                    234:
1.36      jdolecek  235: #define VIOIF_TX_LOCK(_sc)     mutex_enter(&(_sc)->sc_tx_lock)
                    236: #define VIOIF_TX_UNLOCK(_sc)   mutex_exit(&(_sc)->sc_tx_lock)
                    237: #define VIOIF_TX_LOCKED(_sc)   mutex_owned(&(_sc)->sc_tx_lock)
                    238: #define VIOIF_RX_LOCK(_sc)     mutex_enter(&(_sc)->sc_rx_lock)
                    239: #define VIOIF_RX_UNLOCK(_sc)   mutex_exit(&(_sc)->sc_rx_lock)
                    240: #define VIOIF_RX_LOCKED(_sc)   mutex_owned(&(_sc)->sc_rx_lock)
1.7       ozaki-r   241:
1.1       hannken   242: /* cfattach interface functions */
                    243: static int     vioif_match(device_t, cfdata_t, void *);
                    244: static void    vioif_attach(device_t, device_t, void *);
                    245: static void    vioif_deferred_init(device_t);
                    246:
                    247: /* ifnet interface functions */
                    248: static int     vioif_init(struct ifnet *);
                    249: static void    vioif_stop(struct ifnet *, int);
                    250: static void    vioif_start(struct ifnet *);
                    251: static int     vioif_ioctl(struct ifnet *, u_long, void *);
                    252: static void    vioif_watchdog(struct ifnet *);
                    253:
                    254: /* rx */
                    255: static int     vioif_add_rx_mbuf(struct vioif_softc *, int);
                    256: static void    vioif_free_rx_mbuf(struct vioif_softc *, int);
                    257: static void    vioif_populate_rx_mbufs(struct vioif_softc *);
1.12      ozaki-r   258: static void    vioif_populate_rx_mbufs_locked(struct vioif_softc *);
1.1       hannken   259: static int     vioif_rx_deq(struct vioif_softc *);
1.7       ozaki-r   260: static int     vioif_rx_deq_locked(struct vioif_softc *);
1.1       hannken   261: static int     vioif_rx_vq_done(struct virtqueue *);
                    262: static void    vioif_rx_softint(void *);
                    263: static void    vioif_rx_drain(struct vioif_softc *);
                    264:
                    265: /* tx */
                    266: static int     vioif_tx_vq_done(struct virtqueue *);
1.7       ozaki-r   267: static int     vioif_tx_vq_done_locked(struct virtqueue *);
1.1       hannken   268: static void    vioif_tx_drain(struct vioif_softc *);
                    269:
                    270: /* other control */
1.34      ozaki-r   271: static bool    vioif_is_link_up(struct vioif_softc *);
                    272: static void    vioif_update_link_status(struct vioif_softc *);
1.1       hannken   273: static int     vioif_ctrl_rx(struct vioif_softc *, int, bool);
                    274: static int     vioif_set_promisc(struct vioif_softc *, bool);
                    275: static int     vioif_set_allmulti(struct vioif_softc *, bool);
                    276: static int     vioif_set_rx_filter(struct vioif_softc *);
                    277: static int     vioif_rx_filter(struct vioif_softc *);
                    278: static int     vioif_ctrl_vq_done(struct virtqueue *);
1.34      ozaki-r   279: static int     vioif_config_change(struct virtio_softc *);
                    280: static void    vioif_ctl_softint(void *);
1.1       hannken   281:
                    282: CFATTACH_DECL_NEW(vioif, sizeof(struct vioif_softc),
                    283:                  vioif_match, vioif_attach, NULL, NULL);
                    284:
                    285: static int
                    286: vioif_match(device_t parent, cfdata_t match, void *aux)
                    287: {
1.32      jdolecek  288:        struct virtio_attach_args *va = aux;
1.1       hannken   289:
                    290:        if (va->sc_childdevid == PCI_PRODUCT_VIRTIO_NETWORK)
                    291:                return 1;
                    292:
                    293:        return 0;
                    294: }
                    295:
                    296: /* allocate memory */
                    297: /*
                    298:  * dma memory is used for:
1.39      dholland  299:  *   sc_rx_hdrs[slot]:  metadata array for received frames (READ)
1.1       hannken   300:  *   sc_tx_hdrs[slot]:  metadata array for frames to be sent (WRITE)
                    301:  *   sc_ctrl_cmd:       command to be sent via ctrl vq (WRITE)
                    302:  *   sc_ctrl_status:    return value for a command via ctrl vq (READ)
                    303:  *   sc_ctrl_rx:        parameter for a VIRTIO_NET_CTRL_RX class command
                    304:  *                      (WRITE)
                    305:  *   sc_ctrl_mac_tbl_uc: unicast MAC address filter for a VIRTIO_NET_CTRL_MAC
                    306:  *                      class command (WRITE)
                    307:  *   sc_ctrl_mac_tbl_mc: multicast MAC address filter for a VIRTIO_NET_CTRL_MAC
                    308:  *                      class command (WRITE)
                    309:  * sc_ctrl_* structures are allocated only one each; they are protected by
                    310:  * sc_ctrl_inuse variable and sc_ctrl_wait condvar.
                    311:  */
                    312: /*
                    313:  * dynamically allocated memory is used for:
                    314:  *   sc_rxhdr_dmamaps[slot]:   bus_dmamap_t array for sc_rx_hdrs[slot]
                    315:  *   sc_txhdr_dmamaps[slot]:   bus_dmamap_t array for sc_tx_hdrs[slot]
1.39      dholland  316:  *   sc_rx_dmamaps[slot]:      bus_dmamap_t array for received payload
1.1       hannken   317:  *   sc_tx_dmamaps[slot]:      bus_dmamap_t array for sent payload
1.39      dholland  318:  *   sc_rx_mbufs[slot]:                mbuf pointer array for received frames
1.1       hannken   319:  *   sc_tx_mbufs[slot]:                mbuf pointer array for sent frames
                    320:  */
                    321: static int
                    322: vioif_alloc_mems(struct vioif_softc *sc)
                    323: {
                    324:        struct virtio_softc *vsc = sc->sc_virtio;
                    325:        int allocsize, allocsize2, r, rsegs, i;
                    326:        void *vaddr;
                    327:        intptr_t p;
                    328:        int rxqsize, txqsize;
                    329:
1.32      jdolecek  330:        rxqsize = sc->sc_vq[VQ_RX].vq_num;
                    331:        txqsize = sc->sc_vq[VQ_TX].vq_num;
1.1       hannken   332:
                    333:        allocsize = sizeof(struct virtio_net_hdr) * rxqsize;
                    334:        allocsize += sizeof(struct virtio_net_hdr) * txqsize;
1.32      jdolecek  335:        if (sc->sc_has_ctrl) {
1.1       hannken   336:                allocsize += sizeof(struct virtio_net_ctrl_cmd) * 1;
                    337:                allocsize += sizeof(struct virtio_net_ctrl_status) * 1;
                    338:                allocsize += sizeof(struct virtio_net_ctrl_rx) * 1;
                    339:                allocsize += sizeof(struct virtio_net_ctrl_mac_tbl)
                    340:                        + sizeof(struct virtio_net_ctrl_mac_tbl)
                    341:                        + ETHER_ADDR_LEN * VIRTIO_NET_CTRL_MAC_MAXENTRIES;
                    342:        }
1.32      jdolecek  343:        r = bus_dmamem_alloc(virtio_dmat(vsc), allocsize, 0, 0,
1.1       hannken   344:                             &sc->sc_hdr_segs[0], 1, &rsegs, BUS_DMA_NOWAIT);
                    345:        if (r != 0) {
                    346:                aprint_error_dev(sc->sc_dev,
                    347:                                 "DMA memory allocation failed, size %d, "
                    348:                                 "error code %d\n", allocsize, r);
                    349:                goto err_none;
                    350:        }
1.32      jdolecek  351:        r = bus_dmamem_map(virtio_dmat(vsc),
1.1       hannken   352:                           &sc->sc_hdr_segs[0], 1, allocsize,
                    353:                           &vaddr, BUS_DMA_NOWAIT);
                    354:        if (r != 0) {
                    355:                aprint_error_dev(sc->sc_dev,
                    356:                                 "DMA memory map failed, "
                    357:                                 "error code %d\n", r);
                    358:                goto err_dmamem_alloc;
                    359:        }
                    360:        sc->sc_hdrs = vaddr;
                    361:        memset(vaddr, 0, allocsize);
                    362:        p = (intptr_t) vaddr;
                    363:        p += sizeof(struct virtio_net_hdr) * rxqsize;
                    364: #define P(name,size)   do { sc->sc_ ##name = (void*) p;        \
                    365:                             p += size; } while (0)
                    366:        P(tx_hdrs, sizeof(struct virtio_net_hdr) * txqsize);
1.32      jdolecek  367:        if (sc->sc_has_ctrl) {
1.1       hannken   368:                P(ctrl_cmd, sizeof(struct virtio_net_ctrl_cmd));
                    369:                P(ctrl_status, sizeof(struct virtio_net_ctrl_status));
                    370:                P(ctrl_rx, sizeof(struct virtio_net_ctrl_rx));
                    371:                P(ctrl_mac_tbl_uc, sizeof(struct virtio_net_ctrl_mac_tbl));
                    372:                P(ctrl_mac_tbl_mc,
                    373:                  (sizeof(struct virtio_net_ctrl_mac_tbl)
                    374:                   + ETHER_ADDR_LEN * VIRTIO_NET_CTRL_MAC_MAXENTRIES));
                    375:        }
                    376: #undef P
                    377:
                    378:        allocsize2 = sizeof(bus_dmamap_t) * (rxqsize + txqsize);
                    379:        allocsize2 += sizeof(bus_dmamap_t) * (rxqsize + txqsize);
                    380:        allocsize2 += sizeof(struct mbuf*) * (rxqsize + txqsize);
                    381:        sc->sc_arrays = kmem_zalloc(allocsize2, KM_SLEEP);
                    382:        sc->sc_txhdr_dmamaps = sc->sc_arrays + rxqsize;
                    383:        sc->sc_rx_dmamaps = sc->sc_txhdr_dmamaps + txqsize;
                    384:        sc->sc_tx_dmamaps = sc->sc_rx_dmamaps + rxqsize;
                    385:        sc->sc_rx_mbufs = (void*) (sc->sc_tx_dmamaps + txqsize);
                    386:        sc->sc_tx_mbufs = sc->sc_rx_mbufs + rxqsize;
                    387:
                    388: #define C(map, buf, size, nsegs, rw, usage)                            \
                    389:        do {                                                            \
1.32      jdolecek  390:                r = bus_dmamap_create(virtio_dmat(vsc), size, nsegs, size, 0, \
1.1       hannken   391:                                      BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW,  \
                    392:                                      &sc->sc_ ##map);                  \
                    393:                if (r != 0) {                                           \
                    394:                        aprint_error_dev(sc->sc_dev,                    \
                    395:                                         usage " dmamap creation failed, " \
                    396:                                         "error code %d\n", r);         \
                    397:                                         goto err_reqs;                 \
                    398:                }                                                       \
                    399:        } while (0)
                    400: #define C_L1(map, buf, size, nsegs, rw, usage)                         \
                    401:        C(map, buf, size, nsegs, rw, usage);                            \
                    402:        do {                                                            \
1.32      jdolecek  403:                r = bus_dmamap_load(virtio_dmat(vsc), sc->sc_ ##map,    \
1.1       hannken   404:                                    &sc->sc_ ##buf, size, NULL,         \
                    405:                                    BUS_DMA_ ##rw | BUS_DMA_NOWAIT);    \
                    406:                if (r != 0) {                                           \
                    407:                        aprint_error_dev(sc->sc_dev,                    \
                    408:                                         usage " dmamap load failed, "  \
                    409:                                         "error code %d\n", r);         \
                    410:                        goto err_reqs;                                  \
                    411:                }                                                       \
                    412:        } while (0)
                    413: #define C_L2(map, buf, size, nsegs, rw, usage)                         \
                    414:        C(map, buf, size, nsegs, rw, usage);                            \
                    415:        do {                                                            \
1.32      jdolecek  416:                r = bus_dmamap_load(virtio_dmat(vsc), sc->sc_ ##map,    \
1.1       hannken   417:                                    sc->sc_ ##buf, size, NULL,          \
                    418:                                    BUS_DMA_ ##rw | BUS_DMA_NOWAIT);    \
                    419:                if (r != 0) {                                           \
                    420:                        aprint_error_dev(sc->sc_dev,                    \
                    421:                                         usage " dmamap load failed, "  \
                    422:                                         "error code %d\n", r);         \
                    423:                        goto err_reqs;                                  \
                    424:                }                                                       \
                    425:        } while (0)
                    426:        for (i = 0; i < rxqsize; i++) {
                    427:                C_L1(rxhdr_dmamaps[i], rx_hdrs[i],
                    428:                    sizeof(struct virtio_net_hdr), 1,
                    429:                    READ, "rx header");
                    430:                C(rx_dmamaps[i], NULL, MCLBYTES, 1, 0, "rx payload");
                    431:        }
                    432:
                    433:        for (i = 0; i < txqsize; i++) {
1.25      ozaki-r   434:                C_L1(txhdr_dmamaps[i], tx_hdrs[i],
1.1       hannken   435:                    sizeof(struct virtio_net_hdr), 1,
                    436:                    WRITE, "tx header");
1.36      jdolecek  437:                C(tx_dmamaps[i], NULL, ETHER_MAX_LEN, VIRTIO_NET_TX_MAXNSEGS, 0,
1.1       hannken   438:                  "tx payload");
                    439:        }
                    440:
1.32      jdolecek  441:        if (sc->sc_has_ctrl) {
1.1       hannken   442:                /* control vq class & command */
                    443:                C_L2(ctrl_cmd_dmamap, ctrl_cmd,
                    444:                    sizeof(struct virtio_net_ctrl_cmd), 1, WRITE,
                    445:                    "control command");
1.3       christos  446:
1.1       hannken   447:                /* control vq status */
                    448:                C_L2(ctrl_status_dmamap, ctrl_status,
                    449:                    sizeof(struct virtio_net_ctrl_status), 1, READ,
                    450:                    "control status");
                    451:
                    452:                /* control vq rx mode command parameter */
                    453:                C_L2(ctrl_rx_dmamap, ctrl_rx,
                    454:                    sizeof(struct virtio_net_ctrl_rx), 1, WRITE,
                    455:                    "rx mode control command");
                    456:
                    457:                /* control vq MAC filter table for unicast */
                    458:                /* do not load now since its length is variable */
                    459:                C(ctrl_tbl_uc_dmamap, NULL,
                    460:                  sizeof(struct virtio_net_ctrl_mac_tbl) + 0, 1, WRITE,
                    461:                  "unicast MAC address filter command");
                    462:
                    463:                /* control vq MAC filter table for multicast */
                    464:                C(ctrl_tbl_mc_dmamap, NULL,
                    465:                  (sizeof(struct virtio_net_ctrl_mac_tbl)
                    466:                   + ETHER_ADDR_LEN * VIRTIO_NET_CTRL_MAC_MAXENTRIES),
                    467:                  1, WRITE, "multicast MAC address filter command");
                    468:        }
                    469: #undef C_L2
                    470: #undef C_L1
                    471: #undef C
                    472:
                    473:        return 0;
                    474:
                    475: err_reqs:
                    476: #define D(map)                                                         \
                    477:        do {                                                            \
                    478:                if (sc->sc_ ##map) {                                    \
1.32      jdolecek  479:                        bus_dmamap_destroy(virtio_dmat(vsc), sc->sc_ ##map); \
1.1       hannken   480:                        sc->sc_ ##map = NULL;                           \
                    481:                }                                                       \
                    482:        } while (0)
                    483:        D(ctrl_tbl_mc_dmamap);
                    484:        D(ctrl_tbl_uc_dmamap);
                    485:        D(ctrl_rx_dmamap);
                    486:        D(ctrl_status_dmamap);
                    487:        D(ctrl_cmd_dmamap);
                    488:        for (i = 0; i < txqsize; i++) {
                    489:                D(tx_dmamaps[i]);
                    490:                D(txhdr_dmamaps[i]);
                    491:        }
                    492:        for (i = 0; i < rxqsize; i++) {
                    493:                D(rx_dmamaps[i]);
                    494:                D(rxhdr_dmamaps[i]);
                    495:        }
                    496: #undef D
                    497:        if (sc->sc_arrays) {
                    498:                kmem_free(sc->sc_arrays, allocsize2);
                    499:                sc->sc_arrays = 0;
                    500:        }
1.32      jdolecek  501:        bus_dmamem_unmap(virtio_dmat(vsc), sc->sc_hdrs, allocsize);
1.1       hannken   502: err_dmamem_alloc:
1.32      jdolecek  503:        bus_dmamem_free(virtio_dmat(vsc), &sc->sc_hdr_segs[0], 1);
1.1       hannken   504: err_none:
                    505:        return -1;
                    506: }
                    507:
                    508: static void
                    509: vioif_attach(device_t parent, device_t self, void *aux)
                    510: {
                    511:        struct vioif_softc *sc = device_private(self);
                    512:        struct virtio_softc *vsc = device_private(parent);
                    513:        uint32_t features;
                    514:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1.7       ozaki-r   515:        u_int flags;
1.32      jdolecek  516:        int r, nvqs=0, req_flags;
1.1       hannken   517:
1.32      jdolecek  518:        if (virtio_child(vsc) != NULL) {
1.1       hannken   519:                aprint_normal(": child already attached for %s; "
                    520:                              "something wrong...\n",
                    521:                              device_xname(parent));
                    522:                return;
                    523:        }
                    524:
                    525:        sc->sc_dev = self;
                    526:        sc->sc_virtio = vsc;
1.34      ozaki-r   527:        sc->sc_link_active = false;
1.1       hannken   528:
1.32      jdolecek  529:        req_flags = 0;
1.1       hannken   530:
1.7       ozaki-r   531: #ifdef VIOIF_MPSAFE
1.32      jdolecek  532:        req_flags |= VIRTIO_F_PCI_INTR_MPSAFE;
1.7       ozaki-r   533: #endif
1.12      ozaki-r   534: #ifdef VIOIF_SOFTINT_INTR
1.32      jdolecek  535:        req_flags |= VIRTIO_F_PCI_INTR_SOFTINT;
1.12      ozaki-r   536: #endif
1.32      jdolecek  537:        req_flags |= VIRTIO_F_PCI_INTR_MSIX;
                    538:
                    539:        virtio_child_attach_start(vsc, self, IPL_NET, sc->sc_vq,
1.34      ozaki-r   540:            vioif_config_change, virtio_vq_intr, req_flags,
1.32      jdolecek  541:            (VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS | VIRTIO_NET_F_CTRL_VQ |
                    542:             VIRTIO_NET_F_CTRL_RX | VIRTIO_F_NOTIFY_ON_EMPTY),
                    543:            VIRTIO_NET_FLAG_BITS);
                    544:
                    545:        features = virtio_features(vsc);
1.7       ozaki-r   546:
1.1       hannken   547:        if (features & VIRTIO_NET_F_MAC) {
                    548:                sc->sc_mac[0] = virtio_read_device_config_1(vsc,
                    549:                                                    VIRTIO_NET_CONFIG_MAC+0);
                    550:                sc->sc_mac[1] = virtio_read_device_config_1(vsc,
                    551:                                                    VIRTIO_NET_CONFIG_MAC+1);
                    552:                sc->sc_mac[2] = virtio_read_device_config_1(vsc,
                    553:                                                    VIRTIO_NET_CONFIG_MAC+2);
                    554:                sc->sc_mac[3] = virtio_read_device_config_1(vsc,
                    555:                                                    VIRTIO_NET_CONFIG_MAC+3);
                    556:                sc->sc_mac[4] = virtio_read_device_config_1(vsc,
                    557:                                                    VIRTIO_NET_CONFIG_MAC+4);
                    558:                sc->sc_mac[5] = virtio_read_device_config_1(vsc,
                    559:                                                    VIRTIO_NET_CONFIG_MAC+5);
                    560:        } else {
                    561:                /* code stolen from sys/net/if_tap.c */
                    562:                struct timeval tv;
                    563:                uint32_t ui;
                    564:                getmicrouptime(&tv);
                    565:                ui = (tv.tv_sec ^ tv.tv_usec) & 0xffffff;
                    566:                memcpy(sc->sc_mac+3, (uint8_t *)&ui, 3);
                    567:                virtio_write_device_config_1(vsc,
                    568:                                             VIRTIO_NET_CONFIG_MAC+0,
                    569:                                             sc->sc_mac[0]);
                    570:                virtio_write_device_config_1(vsc,
                    571:                                             VIRTIO_NET_CONFIG_MAC+1,
                    572:                                             sc->sc_mac[1]);
                    573:                virtio_write_device_config_1(vsc,
                    574:                                             VIRTIO_NET_CONFIG_MAC+2,
                    575:                                             sc->sc_mac[2]);
                    576:                virtio_write_device_config_1(vsc,
                    577:                                             VIRTIO_NET_CONFIG_MAC+3,
                    578:                                             sc->sc_mac[3]);
                    579:                virtio_write_device_config_1(vsc,
                    580:                                             VIRTIO_NET_CONFIG_MAC+4,
                    581:                                             sc->sc_mac[4]);
                    582:                virtio_write_device_config_1(vsc,
                    583:                                             VIRTIO_NET_CONFIG_MAC+5,
                    584:                                             sc->sc_mac[5]);
                    585:        }
1.32      jdolecek  586:
                    587:        aprint_normal_dev(self, "Ethernet address %s\n", ether_sprintf(sc->sc_mac));
1.1       hannken   588:
1.36      jdolecek  589:        mutex_init(&sc->sc_tx_lock, MUTEX_DEFAULT, IPL_NET);
                    590:        mutex_init(&sc->sc_rx_lock, MUTEX_DEFAULT, IPL_NET);
1.7       ozaki-r   591:        sc->sc_stopping = false;
                    592:
1.17      ozaki-r   593:        /*
                    594:         * Allocating a virtqueue for Rx
                    595:         */
1.32      jdolecek  596:        r = virtio_alloc_vq(vsc, &sc->sc_vq[VQ_RX], VQ_RX,
1.17      ozaki-r   597:            MCLBYTES+sizeof(struct virtio_net_hdr), 2, "rx");
                    598:        if (r != 0)
                    599:                goto err;
1.32      jdolecek  600:        nvqs = 1;
1.19      ozaki-r   601:        sc->sc_vq[VQ_RX].vq_done = vioif_rx_vq_done;
1.17      ozaki-r   602:
                    603:        /*
                    604:         * Allocating a virtqueue for Tx
                    605:         */
1.32      jdolecek  606:        r = virtio_alloc_vq(vsc, &sc->sc_vq[VQ_TX], VQ_TX,
1.17      ozaki-r   607:            (sizeof(struct virtio_net_hdr) + (ETHER_MAX_LEN - ETHER_HDR_LEN)),
                    608:            VIRTIO_NET_TX_MAXNSEGS + 1, "tx");
                    609:        if (r != 0)
                    610:                goto err;
1.32      jdolecek  611:        nvqs = 2;
1.19      ozaki-r   612:        sc->sc_vq[VQ_TX].vq_done = vioif_tx_vq_done;
1.17      ozaki-r   613:
1.19      ozaki-r   614:        virtio_start_vq_intr(vsc, &sc->sc_vq[VQ_RX]);
                    615:        virtio_stop_vq_intr(vsc, &sc->sc_vq[VQ_TX]); /* not urgent; do it later */
1.17      ozaki-r   616:
                    617:        if ((features & VIRTIO_NET_F_CTRL_VQ) &&
                    618:            (features & VIRTIO_NET_F_CTRL_RX)) {
                    619:                /*
                    620:                 * Allocating a virtqueue for control channel
                    621:                 */
1.32      jdolecek  622:                r = virtio_alloc_vq(vsc, &sc->sc_vq[VQ_CTRL], VQ_CTRL,
1.17      ozaki-r   623:                    NBPG, 1, "control");
                    624:                if (r != 0) {
                    625:                        aprint_error_dev(self, "failed to allocate "
                    626:                            "a virtqueue for control channel\n");
                    627:                        goto skip;
1.1       hannken   628:                }
1.17      ozaki-r   629:
1.19      ozaki-r   630:                sc->sc_vq[VQ_CTRL].vq_done = vioif_ctrl_vq_done;
1.17      ozaki-r   631:                cv_init(&sc->sc_ctrl_wait, "ctrl_vq");
                    632:                mutex_init(&sc->sc_ctrl_wait_lock, MUTEX_DEFAULT, IPL_NET);
                    633:                sc->sc_ctrl_inuse = FREE;
1.19      ozaki-r   634:                virtio_start_vq_intr(vsc, &sc->sc_vq[VQ_CTRL]);
1.32      jdolecek  635:                sc->sc_has_ctrl = true;
                    636:                nvqs = 3;
1.1       hannken   637:        }
1.17      ozaki-r   638: skip:
1.1       hannken   639:
1.7       ozaki-r   640: #ifdef VIOIF_MPSAFE
                    641:        flags = SOFTINT_NET | SOFTINT_MPSAFE;
                    642: #else
                    643:        flags = SOFTINT_NET;
                    644: #endif
                    645:        sc->sc_rx_softint = softint_establish(flags, vioif_rx_softint, sc);
1.1       hannken   646:        if (sc->sc_rx_softint == NULL) {
1.34      ozaki-r   647:                aprint_error_dev(self, "cannot establish rx softint\n");
                    648:                goto err;
                    649:        }
                    650:
                    651:        sc->sc_ctl_softint = softint_establish(flags, vioif_ctl_softint, sc);
                    652:        if (sc->sc_ctl_softint == NULL) {
                    653:                aprint_error_dev(self, "cannot establish ctl softint\n");
1.1       hannken   654:                goto err;
                    655:        }
                    656:
                    657:        if (vioif_alloc_mems(sc) < 0)
                    658:                goto err;
                    659:
1.32      jdolecek  660:        if (virtio_child_attach_finish(vsc) != 0)
                    661:                goto err;
                    662:
1.1       hannken   663:        strlcpy(ifp->if_xname, device_xname(self), IFNAMSIZ);
                    664:        ifp->if_softc = sc;
                    665:        ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
                    666:        ifp->if_start = vioif_start;
                    667:        ifp->if_ioctl = vioif_ioctl;
                    668:        ifp->if_init = vioif_init;
                    669:        ifp->if_stop = vioif_stop;
                    670:        ifp->if_capabilities = 0;
                    671:        ifp->if_watchdog = vioif_watchdog;
1.36      jdolecek  672:        IFQ_SET_MAXLEN(&ifp->if_snd, MAX(sc->sc_vq[VQ_TX].vq_num, IFQ_MAXLEN));
                    673:        IFQ_SET_READY(&ifp->if_snd);
1.1       hannken   674:
1.11      ozaki-r   675:        sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
                    676:
1.1       hannken   677:        if_attach(ifp);
1.28      ozaki-r   678:        if_deferred_start_init(ifp, NULL);
1.1       hannken   679:        ether_ifattach(ifp, sc->sc_mac);
                    680:
                    681:        return;
                    682:
                    683: err:
1.36      jdolecek  684:        mutex_destroy(&sc->sc_tx_lock);
                    685:        mutex_destroy(&sc->sc_rx_lock);
1.7       ozaki-r   686:
1.32      jdolecek  687:        if (sc->sc_has_ctrl) {
1.1       hannken   688:                cv_destroy(&sc->sc_ctrl_wait);
                    689:                mutex_destroy(&sc->sc_ctrl_wait_lock);
                    690:        }
1.20      christos  691:
1.32      jdolecek  692:        while (nvqs > 0)
                    693:                virtio_free_vq(vsc, &sc->sc_vq[--nvqs]);
1.20      christos  694:
1.32      jdolecek  695:        virtio_child_attach_failed(vsc);
1.1       hannken   696:        return;
                    697: }
                    698:
                    699: /* we need interrupts to make promiscuous mode off */
                    700: static void
                    701: vioif_deferred_init(device_t self)
                    702: {
                    703:        struct vioif_softc *sc = device_private(self);
                    704:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
                    705:        int r;
                    706:
1.9       ozaki-r   707:        if (ifp->if_flags & IFF_PROMISC)
1.10      ozaki-r   708:                return;
1.9       ozaki-r   709:
1.1       hannken   710:        r =  vioif_set_promisc(sc, false);
                    711:        if (r != 0)
                    712:                aprint_error_dev(self, "resetting promisc mode failed, "
                    713:                                 "errror code %d\n", r);
                    714: }
                    715:
                    716: /*
                    717:  * Interface functions for ifnet
                    718:  */
                    719: static int
                    720: vioif_init(struct ifnet *ifp)
                    721: {
                    722:        struct vioif_softc *sc = ifp->if_softc;
1.33      ozaki-r   723:        struct virtio_softc *vsc = sc->sc_virtio;
1.1       hannken   724:
                    725:        vioif_stop(ifp, 0);
1.7       ozaki-r   726:
1.33      ozaki-r   727:        virtio_reinit_start(vsc);
                    728:        virtio_negotiate_features(vsc, virtio_features(vsc));
                    729:        virtio_start_vq_intr(vsc, &sc->sc_vq[VQ_RX]);
                    730:        virtio_stop_vq_intr(vsc, &sc->sc_vq[VQ_TX]);
                    731:        if (sc->sc_has_ctrl)
                    732:                virtio_start_vq_intr(vsc, &sc->sc_vq[VQ_CTRL]);
                    733:        virtio_reinit_end(vsc);
                    734:
1.8       pooka     735:        if (!sc->sc_deferred_init_done) {
                    736:                sc->sc_deferred_init_done = 1;
1.32      jdolecek  737:                if (sc->sc_has_ctrl)
1.8       pooka     738:                        vioif_deferred_init(sc->sc_dev);
                    739:        }
                    740:
1.7       ozaki-r   741:        /* Have to set false before vioif_populate_rx_mbufs */
                    742:        sc->sc_stopping = false;
                    743:
1.1       hannken   744:        vioif_populate_rx_mbufs(sc);
1.7       ozaki-r   745:
1.34      ozaki-r   746:        vioif_update_link_status(sc);
1.1       hannken   747:        ifp->if_flags |= IFF_RUNNING;
                    748:        ifp->if_flags &= ~IFF_OACTIVE;
                    749:        vioif_rx_filter(sc);
                    750:
                    751:        return 0;
                    752: }
                    753:
                    754: static void
                    755: vioif_stop(struct ifnet *ifp, int disable)
                    756: {
                    757:        struct vioif_softc *sc = ifp->if_softc;
                    758:        struct virtio_softc *vsc = sc->sc_virtio;
                    759:
1.13      ozaki-r   760:        /* Take the locks to ensure that ongoing TX/RX finish */
                    761:        VIOIF_TX_LOCK(sc);
                    762:        VIOIF_RX_LOCK(sc);
1.7       ozaki-r   763:        sc->sc_stopping = true;
1.13      ozaki-r   764:        VIOIF_RX_UNLOCK(sc);
                    765:        VIOIF_TX_UNLOCK(sc);
1.7       ozaki-r   766:
1.33      ozaki-r   767:        /* disable interrupts */
                    768:        virtio_stop_vq_intr(vsc, &sc->sc_vq[VQ_RX]);
                    769:        virtio_stop_vq_intr(vsc, &sc->sc_vq[VQ_TX]);
                    770:        if (sc->sc_has_ctrl)
                    771:                virtio_stop_vq_intr(vsc, &sc->sc_vq[VQ_CTRL]);
                    772:
1.1       hannken   773:        /* only way to stop I/O and DMA is resetting... */
                    774:        virtio_reset(vsc);
                    775:        vioif_rx_deq(sc);
                    776:        vioif_tx_drain(sc);
                    777:        ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
1.34      ozaki-r   778:        sc->sc_link_active = false;
1.1       hannken   779:
                    780:        if (disable)
                    781:                vioif_rx_drain(sc);
                    782: }
                    783:
                    784: static void
                    785: vioif_start(struct ifnet *ifp)
                    786: {
                    787:        struct vioif_softc *sc = ifp->if_softc;
                    788:        struct virtio_softc *vsc = sc->sc_virtio;
1.19      ozaki-r   789:        struct virtqueue *vq = &sc->sc_vq[VQ_TX];
1.1       hannken   790:        struct mbuf *m;
1.36      jdolecek  791:        int queued = 0;
1.1       hannken   792:
1.7       ozaki-r   793:        VIOIF_TX_LOCK(sc);
                    794:
1.34      ozaki-r   795:        if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING ||
                    796:            !sc->sc_link_active)
1.7       ozaki-r   797:                goto out;
                    798:
                    799:        if (sc->sc_stopping)
                    800:                goto out;
1.1       hannken   801:
1.2       jmcneill  802:        for (;;) {
1.1       hannken   803:                int slot, r;
                    804:
1.7       ozaki-r   805:                IFQ_DEQUEUE(&ifp->if_snd, m);
1.2       jmcneill  806:                if (m == NULL)
                    807:                        break;
                    808:
1.1       hannken   809:                r = virtio_enqueue_prep(vsc, vq, &slot);
                    810:                if (r == EAGAIN) {
                    811:                        ifp->if_flags |= IFF_OACTIVE;
1.36      jdolecek  812:                        m_freem(m);
                    813:                        break;
1.1       hannken   814:                }
                    815:                if (r != 0)
                    816:                        panic("enqueue_prep for a tx buffer");
1.36      jdolecek  817:
1.32      jdolecek  818:                r = bus_dmamap_load_mbuf(virtio_dmat(vsc),
1.1       hannken   819:                                         sc->sc_tx_dmamaps[slot],
                    820:                                         m, BUS_DMA_WRITE|BUS_DMA_NOWAIT);
                    821:                if (r != 0) {
1.36      jdolecek  822:                        /* maybe just too fragmented */
                    823:                        struct mbuf *newm;
                    824:
                    825:                        newm = m_defrag(m, M_NOWAIT);
                    826:                        if (newm == NULL) {
                    827:                                aprint_error_dev(sc->sc_dev,
                    828:                                    "m_defrag() failed\n");
                    829:                                goto skip;
                    830:                        }
                    831:
1.37      jdolecek  832:                        m = newm;
1.36      jdolecek  833:                        r = bus_dmamap_load_mbuf(virtio_dmat(vsc),
                    834:                                         sc->sc_tx_dmamaps[slot],
1.37      jdolecek  835:                                         m, BUS_DMA_WRITE|BUS_DMA_NOWAIT);
1.36      jdolecek  836:                        if (r != 0) {
                    837:                                aprint_error_dev(sc->sc_dev,
                    838:                                    "tx dmamap load failed, error code %d\n",
                    839:                                    r);
                    840: skip:
1.37      jdolecek  841:                                m_freem(m);
1.36      jdolecek  842:                                virtio_enqueue_abort(vsc, vq, slot);
                    843:                                continue;
                    844:                        }
1.1       hannken   845:                }
1.36      jdolecek  846:
                    847:                /* This should actually never fail */
1.1       hannken   848:                r = virtio_enqueue_reserve(vsc, vq, slot,
                    849:                                        sc->sc_tx_dmamaps[slot]->dm_nsegs + 1);
                    850:                if (r != 0) {
1.36      jdolecek  851:                        aprint_error_dev(sc->sc_dev,
                    852:                            "virtio_enqueue_reserve failed, error code %d\n",
                    853:                            r);
1.32      jdolecek  854:                        bus_dmamap_unload(virtio_dmat(vsc),
1.1       hannken   855:                                          sc->sc_tx_dmamaps[slot]);
1.36      jdolecek  856:                        /* slot already freed by virtio_enqueue_reserve */
1.37      jdolecek  857:                        m_freem(m);
1.36      jdolecek  858:                        continue;
1.1       hannken   859:                }
1.7       ozaki-r   860:
1.1       hannken   861:                sc->sc_tx_mbufs[slot] = m;
                    862:
                    863:                memset(&sc->sc_tx_hdrs[slot], 0, sizeof(struct virtio_net_hdr));
1.32      jdolecek  864:                bus_dmamap_sync(virtio_dmat(vsc), sc->sc_tx_dmamaps[slot],
1.1       hannken   865:                                0, sc->sc_tx_dmamaps[slot]->dm_mapsize,
                    866:                                BUS_DMASYNC_PREWRITE);
1.32      jdolecek  867:                bus_dmamap_sync(virtio_dmat(vsc), sc->sc_txhdr_dmamaps[slot],
1.1       hannken   868:                                0, sc->sc_txhdr_dmamaps[slot]->dm_mapsize,
                    869:                                BUS_DMASYNC_PREWRITE);
                    870:                virtio_enqueue(vsc, vq, slot, sc->sc_txhdr_dmamaps[slot], true);
                    871:                virtio_enqueue(vsc, vq, slot, sc->sc_tx_dmamaps[slot], true);
                    872:                virtio_enqueue_commit(vsc, vq, slot, false);
1.36      jdolecek  873:
1.1       hannken   874:                queued++;
                    875:                bpf_mtap(ifp, m);
                    876:        }
                    877:
                    878:        if (queued > 0) {
                    879:                virtio_enqueue_commit(vsc, vq, -1, true);
                    880:                ifp->if_timer = 5;
                    881:        }
1.7       ozaki-r   882:
                    883: out:
                    884:        VIOIF_TX_UNLOCK(sc);
1.1       hannken   885: }
                    886:
                    887: static int
                    888: vioif_ioctl(struct ifnet *ifp, u_long cmd, void *data)
                    889: {
                    890:        int s, r;
                    891:
                    892:        s = splnet();
                    893:
                    894:        r = ether_ioctl(ifp, cmd, data);
                    895:        if ((r == 0 && cmd == SIOCSIFFLAGS) ||
                    896:            (r == ENETRESET && (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI))) {
                    897:                if (ifp->if_flags & IFF_RUNNING)
                    898:                        r = vioif_rx_filter(ifp->if_softc);
                    899:                else
                    900:                        r = 0;
                    901:        }
                    902:
                    903:        splx(s);
                    904:
                    905:        return r;
                    906: }
                    907:
                    908: void
                    909: vioif_watchdog(struct ifnet *ifp)
                    910: {
                    911:        struct vioif_softc *sc = ifp->if_softc;
                    912:
                    913:        if (ifp->if_flags & IFF_RUNNING)
1.19      ozaki-r   914:                vioif_tx_vq_done(&sc->sc_vq[VQ_TX]);
1.1       hannken   915: }
                    916:
                    917:
                    918: /*
1.39      dholland  919:  * Receive implementation
1.1       hannken   920:  */
1.39      dholland  921: /* allocate and initialize a mbuf for receive */
1.1       hannken   922: static int
                    923: vioif_add_rx_mbuf(struct vioif_softc *sc, int i)
                    924: {
                    925:        struct mbuf *m;
                    926:        int r;
                    927:
                    928:        MGETHDR(m, M_DONTWAIT, MT_DATA);
                    929:        if (m == NULL)
                    930:                return ENOBUFS;
                    931:        MCLGET(m, M_DONTWAIT);
                    932:        if ((m->m_flags & M_EXT) == 0) {
                    933:                m_freem(m);
                    934:                return ENOBUFS;
                    935:        }
                    936:        sc->sc_rx_mbufs[i] = m;
                    937:        m->m_len = m->m_pkthdr.len = m->m_ext.ext_size;
1.32      jdolecek  938:        r = bus_dmamap_load_mbuf(virtio_dmat(sc->sc_virtio),
1.1       hannken   939:                                 sc->sc_rx_dmamaps[i],
                    940:                                 m, BUS_DMA_READ|BUS_DMA_NOWAIT);
                    941:        if (r) {
                    942:                m_freem(m);
                    943:                sc->sc_rx_mbufs[i] = 0;
                    944:                return r;
                    945:        }
                    946:
                    947:        return 0;
                    948: }
                    949:
1.39      dholland  950: /* free a mbuf for receive */
1.1       hannken   951: static void
                    952: vioif_free_rx_mbuf(struct vioif_softc *sc, int i)
                    953: {
1.32      jdolecek  954:        bus_dmamap_unload(virtio_dmat(sc->sc_virtio), sc->sc_rx_dmamaps[i]);
1.1       hannken   955:        m_freem(sc->sc_rx_mbufs[i]);
                    956:        sc->sc_rx_mbufs[i] = NULL;
                    957: }
                    958:
1.39      dholland  959: /* add mbufs for all the empty receive slots */
1.1       hannken   960: static void
                    961: vioif_populate_rx_mbufs(struct vioif_softc *sc)
                    962: {
1.12      ozaki-r   963:        VIOIF_RX_LOCK(sc);
                    964:        vioif_populate_rx_mbufs_locked(sc);
                    965:        VIOIF_RX_UNLOCK(sc);
                    966: }
                    967:
                    968: static void
                    969: vioif_populate_rx_mbufs_locked(struct vioif_softc *sc)
                    970: {
1.1       hannken   971:        struct virtio_softc *vsc = sc->sc_virtio;
                    972:        int i, r, ndone = 0;
1.19      ozaki-r   973:        struct virtqueue *vq = &sc->sc_vq[VQ_RX];
1.1       hannken   974:
1.12      ozaki-r   975:        KASSERT(VIOIF_RX_LOCKED(sc));
1.7       ozaki-r   976:
                    977:        if (sc->sc_stopping)
1.12      ozaki-r   978:                return;
1.7       ozaki-r   979:
1.1       hannken   980:        for (i = 0; i < vq->vq_num; i++) {
                    981:                int slot;
                    982:                r = virtio_enqueue_prep(vsc, vq, &slot);
                    983:                if (r == EAGAIN)
                    984:                        break;
                    985:                if (r != 0)
                    986:                        panic("enqueue_prep for rx buffers");
                    987:                if (sc->sc_rx_mbufs[slot] == NULL) {
                    988:                        r = vioif_add_rx_mbuf(sc, slot);
                    989:                        if (r != 0) {
                    990:                                printf("%s: rx mbuf allocation failed, "
                    991:                                       "error code %d\n",
                    992:                                       device_xname(sc->sc_dev), r);
                    993:                                break;
                    994:                        }
                    995:                }
                    996:                r = virtio_enqueue_reserve(vsc, vq, slot,
                    997:                                        sc->sc_rx_dmamaps[slot]->dm_nsegs + 1);
                    998:                if (r != 0) {
                    999:                        vioif_free_rx_mbuf(sc, slot);
                   1000:                        break;
                   1001:                }
1.32      jdolecek 1002:                bus_dmamap_sync(virtio_dmat(vsc), sc->sc_rxhdr_dmamaps[slot],
1.1       hannken  1003:                        0, sizeof(struct virtio_net_hdr), BUS_DMASYNC_PREREAD);
1.32      jdolecek 1004:                bus_dmamap_sync(virtio_dmat(vsc), sc->sc_rx_dmamaps[slot],
1.1       hannken  1005:                        0, MCLBYTES, BUS_DMASYNC_PREREAD);
                   1006:                virtio_enqueue(vsc, vq, slot, sc->sc_rxhdr_dmamaps[slot], false);
                   1007:                virtio_enqueue(vsc, vq, slot, sc->sc_rx_dmamaps[slot], false);
                   1008:                virtio_enqueue_commit(vsc, vq, slot, false);
                   1009:                ndone++;
                   1010:        }
                   1011:        if (ndone > 0)
                   1012:                virtio_enqueue_commit(vsc, vq, -1, true);
                   1013: }
                   1014:
1.39      dholland 1015: /* dequeue received packets */
1.1       hannken  1016: static int
                   1017: vioif_rx_deq(struct vioif_softc *sc)
                   1018: {
1.7       ozaki-r  1019:        int r;
                   1020:
                   1021:        KASSERT(sc->sc_stopping);
                   1022:
                   1023:        VIOIF_RX_LOCK(sc);
                   1024:        r = vioif_rx_deq_locked(sc);
                   1025:        VIOIF_RX_UNLOCK(sc);
                   1026:
                   1027:        return r;
                   1028: }
                   1029:
1.39      dholland 1030: /* dequeue received packets */
1.7       ozaki-r  1031: static int
                   1032: vioif_rx_deq_locked(struct vioif_softc *sc)
                   1033: {
1.1       hannken  1034:        struct virtio_softc *vsc = sc->sc_virtio;
1.19      ozaki-r  1035:        struct virtqueue *vq = &sc->sc_vq[VQ_RX];
1.1       hannken  1036:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
                   1037:        struct mbuf *m;
                   1038:        int r = 0;
                   1039:        int slot, len;
                   1040:
1.7       ozaki-r  1041:        KASSERT(VIOIF_RX_LOCKED(sc));
                   1042:
1.1       hannken  1043:        while (virtio_dequeue(vsc, vq, &slot, &len) == 0) {
                   1044:                len -= sizeof(struct virtio_net_hdr);
                   1045:                r = 1;
1.32      jdolecek 1046:                bus_dmamap_sync(virtio_dmat(vsc), sc->sc_rxhdr_dmamaps[slot],
1.1       hannken  1047:                                0, sizeof(struct virtio_net_hdr),
                   1048:                                BUS_DMASYNC_POSTREAD);
1.32      jdolecek 1049:                bus_dmamap_sync(virtio_dmat(vsc), sc->sc_rx_dmamaps[slot],
1.1       hannken  1050:                                0, MCLBYTES,
                   1051:                                BUS_DMASYNC_POSTREAD);
                   1052:                m = sc->sc_rx_mbufs[slot];
                   1053:                KASSERT(m != NULL);
1.32      jdolecek 1054:                bus_dmamap_unload(virtio_dmat(vsc), sc->sc_rx_dmamaps[slot]);
1.1       hannken  1055:                sc->sc_rx_mbufs[slot] = 0;
                   1056:                virtio_dequeue_commit(vsc, vq, slot);
1.24      ozaki-r  1057:                m_set_rcvif(m, ifp);
1.1       hannken  1058:                m->m_len = m->m_pkthdr.len = len;
1.7       ozaki-r  1059:
                   1060:                VIOIF_RX_UNLOCK(sc);
1.22      ozaki-r  1061:                if_percpuq_enqueue(ifp->if_percpuq, m);
1.7       ozaki-r  1062:                VIOIF_RX_LOCK(sc);
                   1063:
                   1064:                if (sc->sc_stopping)
                   1065:                        break;
1.1       hannken  1066:        }
1.3       christos 1067:
1.1       hannken  1068:        return r;
                   1069: }
                   1070:
                   1071: /* rx interrupt; call _dequeue above and schedule a softint */
                   1072: static int
                   1073: vioif_rx_vq_done(struct virtqueue *vq)
                   1074: {
                   1075:        struct virtio_softc *vsc = vq->vq_owner;
1.32      jdolecek 1076:        struct vioif_softc *sc = device_private(virtio_child(vsc));
1.7       ozaki-r  1077:        int r = 0;
                   1078:
1.12      ozaki-r  1079: #ifdef VIOIF_SOFTINT_INTR
                   1080:        KASSERT(!cpu_intr_p());
                   1081: #endif
                   1082:
1.7       ozaki-r  1083:        VIOIF_RX_LOCK(sc);
                   1084:
                   1085:        if (sc->sc_stopping)
                   1086:                goto out;
1.1       hannken  1087:
1.7       ozaki-r  1088:        r = vioif_rx_deq_locked(sc);
1.1       hannken  1089:        if (r)
1.12      ozaki-r  1090: #ifdef VIOIF_SOFTINT_INTR
                   1091:                vioif_populate_rx_mbufs_locked(sc);
                   1092: #else
1.1       hannken  1093:                softint_schedule(sc->sc_rx_softint);
1.12      ozaki-r  1094: #endif
1.1       hannken  1095:
1.7       ozaki-r  1096: out:
                   1097:        VIOIF_RX_UNLOCK(sc);
1.1       hannken  1098:        return r;
                   1099: }
                   1100:
1.39      dholland 1101: /* softint: enqueue receive requests for new incoming packets */
1.1       hannken  1102: static void
                   1103: vioif_rx_softint(void *arg)
                   1104: {
                   1105:        struct vioif_softc *sc = arg;
                   1106:
                   1107:        vioif_populate_rx_mbufs(sc);
                   1108: }
                   1109:
                   1110: /* free all the mbufs; called from if_stop(disable) */
                   1111: static void
                   1112: vioif_rx_drain(struct vioif_softc *sc)
                   1113: {
1.19      ozaki-r  1114:        struct virtqueue *vq = &sc->sc_vq[VQ_RX];
1.1       hannken  1115:        int i;
                   1116:
                   1117:        for (i = 0; i < vq->vq_num; i++) {
                   1118:                if (sc->sc_rx_mbufs[i] == NULL)
                   1119:                        continue;
                   1120:                vioif_free_rx_mbuf(sc, i);
                   1121:        }
                   1122: }
                   1123:
                   1124:
                   1125: /*
                   1126:  * Transmition implementation
                   1127:  */
                   1128: /* actual transmission is done in if_start */
                   1129: /* tx interrupt; dequeue and free mbufs */
                   1130: /*
                   1131:  * tx interrupt is actually disabled; this should be called upon
                   1132:  * tx vq full and watchdog
                   1133:  */
                   1134: static int
                   1135: vioif_tx_vq_done(struct virtqueue *vq)
                   1136: {
                   1137:        struct virtio_softc *vsc = vq->vq_owner;
1.32      jdolecek 1138:        struct vioif_softc *sc = device_private(virtio_child(vsc));
1.23      pooka    1139:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1.7       ozaki-r  1140:        int r = 0;
                   1141:
                   1142:        VIOIF_TX_LOCK(sc);
                   1143:
                   1144:        if (sc->sc_stopping)
                   1145:                goto out;
                   1146:
                   1147:        r = vioif_tx_vq_done_locked(vq);
                   1148:
                   1149: out:
                   1150:        VIOIF_TX_UNLOCK(sc);
1.23      pooka    1151:        if (r)
1.28      ozaki-r  1152:                if_schedule_deferred_start(ifp);
1.7       ozaki-r  1153:        return r;
                   1154: }
                   1155:
                   1156: static int
                   1157: vioif_tx_vq_done_locked(struct virtqueue *vq)
                   1158: {
                   1159:        struct virtio_softc *vsc = vq->vq_owner;
1.32      jdolecek 1160:        struct vioif_softc *sc = device_private(virtio_child(vsc));
1.1       hannken  1161:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
                   1162:        struct mbuf *m;
                   1163:        int r = 0;
                   1164:        int slot, len;
                   1165:
1.7       ozaki-r  1166:        KASSERT(VIOIF_TX_LOCKED(sc));
                   1167:
1.1       hannken  1168:        while (virtio_dequeue(vsc, vq, &slot, &len) == 0) {
                   1169:                r++;
1.32      jdolecek 1170:                bus_dmamap_sync(virtio_dmat(vsc), sc->sc_txhdr_dmamaps[slot],
1.1       hannken  1171:                                0, sizeof(struct virtio_net_hdr),
                   1172:                                BUS_DMASYNC_POSTWRITE);
1.32      jdolecek 1173:                bus_dmamap_sync(virtio_dmat(vsc), sc->sc_tx_dmamaps[slot],
1.1       hannken  1174:                                0, sc->sc_tx_dmamaps[slot]->dm_mapsize,
                   1175:                                BUS_DMASYNC_POSTWRITE);
                   1176:                m = sc->sc_tx_mbufs[slot];
1.32      jdolecek 1177:                bus_dmamap_unload(virtio_dmat(vsc), sc->sc_tx_dmamaps[slot]);
1.1       hannken  1178:                sc->sc_tx_mbufs[slot] = 0;
                   1179:                virtio_dequeue_commit(vsc, vq, slot);
                   1180:                ifp->if_opackets++;
                   1181:                m_freem(m);
                   1182:        }
                   1183:
                   1184:        if (r)
                   1185:                ifp->if_flags &= ~IFF_OACTIVE;
                   1186:        return r;
                   1187: }
                   1188:
                   1189: /* free all the mbufs already put on vq; called from if_stop(disable) */
                   1190: static void
                   1191: vioif_tx_drain(struct vioif_softc *sc)
                   1192: {
                   1193:        struct virtio_softc *vsc = sc->sc_virtio;
1.19      ozaki-r  1194:        struct virtqueue *vq = &sc->sc_vq[VQ_TX];
1.1       hannken  1195:        int i;
                   1196:
1.7       ozaki-r  1197:        KASSERT(sc->sc_stopping);
                   1198:
1.1       hannken  1199:        for (i = 0; i < vq->vq_num; i++) {
                   1200:                if (sc->sc_tx_mbufs[i] == NULL)
                   1201:                        continue;
1.32      jdolecek 1202:                bus_dmamap_unload(virtio_dmat(vsc), sc->sc_tx_dmamaps[i]);
1.1       hannken  1203:                m_freem(sc->sc_tx_mbufs[i]);
                   1204:                sc->sc_tx_mbufs[i] = NULL;
                   1205:        }
                   1206: }
                   1207:
                   1208: /*
                   1209:  * Control vq
                   1210:  */
                   1211: /* issue a VIRTIO_NET_CTRL_RX class command and wait for completion */
                   1212: static int
                   1213: vioif_ctrl_rx(struct vioif_softc *sc, int cmd, bool onoff)
                   1214: {
                   1215:        struct virtio_softc *vsc = sc->sc_virtio;
1.19      ozaki-r  1216:        struct virtqueue *vq = &sc->sc_vq[VQ_CTRL];
1.1       hannken  1217:        int r, slot;
                   1218:
1.32      jdolecek 1219:        if (!sc->sc_has_ctrl)
1.1       hannken  1220:                return ENOTSUP;
                   1221:
                   1222:        mutex_enter(&sc->sc_ctrl_wait_lock);
                   1223:        while (sc->sc_ctrl_inuse != FREE)
                   1224:                cv_wait(&sc->sc_ctrl_wait, &sc->sc_ctrl_wait_lock);
                   1225:        sc->sc_ctrl_inuse = INUSE;
                   1226:        mutex_exit(&sc->sc_ctrl_wait_lock);
                   1227:
                   1228:        sc->sc_ctrl_cmd->class = VIRTIO_NET_CTRL_RX;
                   1229:        sc->sc_ctrl_cmd->command = cmd;
                   1230:        sc->sc_ctrl_rx->onoff = onoff;
                   1231:
1.32      jdolecek 1232:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_cmd_dmamap,
1.1       hannken  1233:                        0, sizeof(struct virtio_net_ctrl_cmd),
                   1234:                        BUS_DMASYNC_PREWRITE);
1.32      jdolecek 1235:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_rx_dmamap,
1.1       hannken  1236:                        0, sizeof(struct virtio_net_ctrl_rx),
                   1237:                        BUS_DMASYNC_PREWRITE);
1.32      jdolecek 1238:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_status_dmamap,
1.1       hannken  1239:                        0, sizeof(struct virtio_net_ctrl_status),
                   1240:                        BUS_DMASYNC_PREREAD);
                   1241:
                   1242:        r = virtio_enqueue_prep(vsc, vq, &slot);
                   1243:        if (r != 0)
                   1244:                panic("%s: control vq busy!?", device_xname(sc->sc_dev));
                   1245:        r = virtio_enqueue_reserve(vsc, vq, slot, 3);
                   1246:        if (r != 0)
                   1247:                panic("%s: control vq busy!?", device_xname(sc->sc_dev));
                   1248:        virtio_enqueue(vsc, vq, slot, sc->sc_ctrl_cmd_dmamap, true);
                   1249:        virtio_enqueue(vsc, vq, slot, sc->sc_ctrl_rx_dmamap, true);
                   1250:        virtio_enqueue(vsc, vq, slot, sc->sc_ctrl_status_dmamap, false);
                   1251:        virtio_enqueue_commit(vsc, vq, slot, true);
                   1252:
                   1253:        /* wait for done */
                   1254:        mutex_enter(&sc->sc_ctrl_wait_lock);
                   1255:        while (sc->sc_ctrl_inuse != DONE)
                   1256:                cv_wait(&sc->sc_ctrl_wait, &sc->sc_ctrl_wait_lock);
                   1257:        mutex_exit(&sc->sc_ctrl_wait_lock);
                   1258:        /* already dequeueued */
                   1259:
1.32      jdolecek 1260:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_cmd_dmamap, 0,
1.1       hannken  1261:                        sizeof(struct virtio_net_ctrl_cmd),
                   1262:                        BUS_DMASYNC_POSTWRITE);
1.32      jdolecek 1263:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_rx_dmamap, 0,
1.1       hannken  1264:                        sizeof(struct virtio_net_ctrl_rx),
                   1265:                        BUS_DMASYNC_POSTWRITE);
1.32      jdolecek 1266:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_status_dmamap, 0,
1.1       hannken  1267:                        sizeof(struct virtio_net_ctrl_status),
                   1268:                        BUS_DMASYNC_POSTREAD);
                   1269:
                   1270:        if (sc->sc_ctrl_status->ack == VIRTIO_NET_OK)
                   1271:                r = 0;
                   1272:        else {
                   1273:                printf("%s: failed setting rx mode\n",
                   1274:                       device_xname(sc->sc_dev));
                   1275:                r = EIO;
                   1276:        }
                   1277:
                   1278:        mutex_enter(&sc->sc_ctrl_wait_lock);
                   1279:        sc->sc_ctrl_inuse = FREE;
                   1280:        cv_signal(&sc->sc_ctrl_wait);
                   1281:        mutex_exit(&sc->sc_ctrl_wait_lock);
1.3       christos 1282:
1.1       hannken  1283:        return r;
                   1284: }
                   1285:
                   1286: static int
                   1287: vioif_set_promisc(struct vioif_softc *sc, bool onoff)
                   1288: {
                   1289:        int r;
                   1290:
                   1291:        r = vioif_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_PROMISC, onoff);
                   1292:
                   1293:        return r;
                   1294: }
                   1295:
                   1296: static int
                   1297: vioif_set_allmulti(struct vioif_softc *sc, bool onoff)
                   1298: {
                   1299:        int r;
                   1300:
                   1301:        r = vioif_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, onoff);
                   1302:
                   1303:        return r;
                   1304: }
                   1305:
                   1306: /* issue VIRTIO_NET_CTRL_MAC_TABLE_SET command and wait for completion */
                   1307: static int
                   1308: vioif_set_rx_filter(struct vioif_softc *sc)
                   1309: {
                   1310:        /* filter already set in sc_ctrl_mac_tbl */
                   1311:        struct virtio_softc *vsc = sc->sc_virtio;
1.19      ozaki-r  1312:        struct virtqueue *vq = &sc->sc_vq[VQ_CTRL];
1.1       hannken  1313:        int r, slot;
                   1314:
1.32      jdolecek 1315:        if (!sc->sc_has_ctrl)
1.1       hannken  1316:                return ENOTSUP;
                   1317:
                   1318:        mutex_enter(&sc->sc_ctrl_wait_lock);
                   1319:        while (sc->sc_ctrl_inuse != FREE)
                   1320:                cv_wait(&sc->sc_ctrl_wait, &sc->sc_ctrl_wait_lock);
                   1321:        sc->sc_ctrl_inuse = INUSE;
                   1322:        mutex_exit(&sc->sc_ctrl_wait_lock);
                   1323:
                   1324:        sc->sc_ctrl_cmd->class = VIRTIO_NET_CTRL_MAC;
                   1325:        sc->sc_ctrl_cmd->command = VIRTIO_NET_CTRL_MAC_TABLE_SET;
                   1326:
1.32      jdolecek 1327:        r = bus_dmamap_load(virtio_dmat(vsc), sc->sc_ctrl_tbl_uc_dmamap,
1.1       hannken  1328:                            sc->sc_ctrl_mac_tbl_uc,
                   1329:                            (sizeof(struct virtio_net_ctrl_mac_tbl)
                   1330:                          + ETHER_ADDR_LEN * sc->sc_ctrl_mac_tbl_uc->nentries),
                   1331:                            NULL, BUS_DMA_WRITE|BUS_DMA_NOWAIT);
                   1332:        if (r) {
                   1333:                printf("%s: control command dmamap load failed, "
                   1334:                       "error code %d\n", device_xname(sc->sc_dev), r);
                   1335:                goto out;
                   1336:        }
1.32      jdolecek 1337:        r = bus_dmamap_load(virtio_dmat(vsc), sc->sc_ctrl_tbl_mc_dmamap,
1.1       hannken  1338:                            sc->sc_ctrl_mac_tbl_mc,
                   1339:                            (sizeof(struct virtio_net_ctrl_mac_tbl)
                   1340:                          + ETHER_ADDR_LEN * sc->sc_ctrl_mac_tbl_mc->nentries),
                   1341:                            NULL, BUS_DMA_WRITE|BUS_DMA_NOWAIT);
                   1342:        if (r) {
                   1343:                printf("%s: control command dmamap load failed, "
                   1344:                       "error code %d\n", device_xname(sc->sc_dev), r);
1.32      jdolecek 1345:                bus_dmamap_unload(virtio_dmat(vsc), sc->sc_ctrl_tbl_uc_dmamap);
1.1       hannken  1346:                goto out;
                   1347:        }
                   1348:
1.32      jdolecek 1349:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_cmd_dmamap,
1.1       hannken  1350:                        0, sizeof(struct virtio_net_ctrl_cmd),
                   1351:                        BUS_DMASYNC_PREWRITE);
1.32      jdolecek 1352:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_tbl_uc_dmamap, 0,
1.1       hannken  1353:                        (sizeof(struct virtio_net_ctrl_mac_tbl)
                   1354:                         + ETHER_ADDR_LEN * sc->sc_ctrl_mac_tbl_uc->nentries),
                   1355:                        BUS_DMASYNC_PREWRITE);
1.32      jdolecek 1356:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_tbl_mc_dmamap, 0,
1.1       hannken  1357:                        (sizeof(struct virtio_net_ctrl_mac_tbl)
                   1358:                         + ETHER_ADDR_LEN * sc->sc_ctrl_mac_tbl_mc->nentries),
                   1359:                        BUS_DMASYNC_PREWRITE);
1.32      jdolecek 1360:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_status_dmamap,
1.1       hannken  1361:                        0, sizeof(struct virtio_net_ctrl_status),
                   1362:                        BUS_DMASYNC_PREREAD);
                   1363:
                   1364:        r = virtio_enqueue_prep(vsc, vq, &slot);
                   1365:        if (r != 0)
                   1366:                panic("%s: control vq busy!?", device_xname(sc->sc_dev));
                   1367:        r = virtio_enqueue_reserve(vsc, vq, slot, 4);
                   1368:        if (r != 0)
                   1369:                panic("%s: control vq busy!?", device_xname(sc->sc_dev));
                   1370:        virtio_enqueue(vsc, vq, slot, sc->sc_ctrl_cmd_dmamap, true);
                   1371:        virtio_enqueue(vsc, vq, slot, sc->sc_ctrl_tbl_uc_dmamap, true);
                   1372:        virtio_enqueue(vsc, vq, slot, sc->sc_ctrl_tbl_mc_dmamap, true);
                   1373:        virtio_enqueue(vsc, vq, slot, sc->sc_ctrl_status_dmamap, false);
                   1374:        virtio_enqueue_commit(vsc, vq, slot, true);
                   1375:
                   1376:        /* wait for done */
                   1377:        mutex_enter(&sc->sc_ctrl_wait_lock);
                   1378:        while (sc->sc_ctrl_inuse != DONE)
                   1379:                cv_wait(&sc->sc_ctrl_wait, &sc->sc_ctrl_wait_lock);
                   1380:        mutex_exit(&sc->sc_ctrl_wait_lock);
                   1381:        /* already dequeueued */
                   1382:
1.32      jdolecek 1383:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_cmd_dmamap, 0,
1.1       hannken  1384:                        sizeof(struct virtio_net_ctrl_cmd),
                   1385:                        BUS_DMASYNC_POSTWRITE);
1.32      jdolecek 1386:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_tbl_uc_dmamap, 0,
1.1       hannken  1387:                        (sizeof(struct virtio_net_ctrl_mac_tbl)
                   1388:                         + ETHER_ADDR_LEN * sc->sc_ctrl_mac_tbl_uc->nentries),
                   1389:                        BUS_DMASYNC_POSTWRITE);
1.32      jdolecek 1390:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_tbl_mc_dmamap, 0,
1.1       hannken  1391:                        (sizeof(struct virtio_net_ctrl_mac_tbl)
                   1392:                         + ETHER_ADDR_LEN * sc->sc_ctrl_mac_tbl_mc->nentries),
                   1393:                        BUS_DMASYNC_POSTWRITE);
1.32      jdolecek 1394:        bus_dmamap_sync(virtio_dmat(vsc), sc->sc_ctrl_status_dmamap, 0,
1.1       hannken  1395:                        sizeof(struct virtio_net_ctrl_status),
                   1396:                        BUS_DMASYNC_POSTREAD);
1.32      jdolecek 1397:        bus_dmamap_unload(virtio_dmat(vsc), sc->sc_ctrl_tbl_uc_dmamap);
                   1398:        bus_dmamap_unload(virtio_dmat(vsc), sc->sc_ctrl_tbl_mc_dmamap);
1.1       hannken  1399:
                   1400:        if (sc->sc_ctrl_status->ack == VIRTIO_NET_OK)
                   1401:                r = 0;
                   1402:        else {
                   1403:                printf("%s: failed setting rx filter\n",
                   1404:                       device_xname(sc->sc_dev));
                   1405:                r = EIO;
                   1406:        }
                   1407:
                   1408: out:
                   1409:        mutex_enter(&sc->sc_ctrl_wait_lock);
                   1410:        sc->sc_ctrl_inuse = FREE;
                   1411:        cv_signal(&sc->sc_ctrl_wait);
                   1412:        mutex_exit(&sc->sc_ctrl_wait_lock);
1.3       christos 1413:
1.1       hannken  1414:        return r;
                   1415: }
                   1416:
                   1417: /* ctrl vq interrupt; wake up the command issuer */
                   1418: static int
                   1419: vioif_ctrl_vq_done(struct virtqueue *vq)
                   1420: {
                   1421:        struct virtio_softc *vsc = vq->vq_owner;
1.32      jdolecek 1422:        struct vioif_softc *sc = device_private(virtio_child(vsc));
1.1       hannken  1423:        int r, slot;
                   1424:
                   1425:        r = virtio_dequeue(vsc, vq, &slot, NULL);
                   1426:        if (r == ENOENT)
                   1427:                return 0;
                   1428:        virtio_dequeue_commit(vsc, vq, slot);
                   1429:
                   1430:        mutex_enter(&sc->sc_ctrl_wait_lock);
                   1431:        sc->sc_ctrl_inuse = DONE;
                   1432:        cv_signal(&sc->sc_ctrl_wait);
                   1433:        mutex_exit(&sc->sc_ctrl_wait_lock);
                   1434:
                   1435:        return 1;
                   1436: }
                   1437:
                   1438: /*
                   1439:  * If IFF_PROMISC requested,  set promiscuous
                   1440:  * If multicast filter small enough (<=MAXENTRIES) set rx filter
                   1441:  * If large multicast filter exist use ALLMULTI
                   1442:  */
                   1443: /*
                   1444:  * If setting rx filter fails fall back to ALLMULTI
                   1445:  * If ALLMULTI fails fall back to PROMISC
                   1446:  */
                   1447: static int
                   1448: vioif_rx_filter(struct vioif_softc *sc)
                   1449: {
                   1450:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
                   1451:        struct ether_multi *enm;
                   1452:        struct ether_multistep step;
                   1453:        int nentries;
                   1454:        int promisc = 0, allmulti = 0, rxfilter = 0;
                   1455:        int r;
                   1456:
1.32      jdolecek 1457:        if (!sc->sc_has_ctrl) { /* no ctrl vq; always promisc */
1.1       hannken  1458:                ifp->if_flags |= IFF_PROMISC;
                   1459:                return 0;
                   1460:        }
                   1461:
                   1462:        if (ifp->if_flags & IFF_PROMISC) {
                   1463:                promisc = 1;
                   1464:                goto set;
                   1465:        }
                   1466:
                   1467:        nentries = -1;
1.30      ozaki-r  1468:        ETHER_LOCK(&sc->sc_ethercom);
1.1       hannken  1469:        ETHER_FIRST_MULTI(step, &sc->sc_ethercom, enm);
                   1470:        while (nentries++, enm != NULL) {
                   1471:                if (nentries >= VIRTIO_NET_CTRL_MAC_MAXENTRIES) {
                   1472:                        allmulti = 1;
1.31      ozaki-r  1473:                        goto set_unlock;
1.1       hannken  1474:                }
                   1475:                if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
                   1476:                           ETHER_ADDR_LEN)) {
                   1477:                        allmulti = 1;
1.31      ozaki-r  1478:                        goto set_unlock;
1.1       hannken  1479:                }
                   1480:                memcpy(sc->sc_ctrl_mac_tbl_mc->macs[nentries],
                   1481:                       enm->enm_addrlo, ETHER_ADDR_LEN);
                   1482:                ETHER_NEXT_MULTI(step, enm);
                   1483:        }
                   1484:        rxfilter = 1;
                   1485:
1.31      ozaki-r  1486: set_unlock:
1.30      ozaki-r  1487:        ETHER_UNLOCK(&sc->sc_ethercom);
                   1488:
1.31      ozaki-r  1489: set:
1.1       hannken  1490:        if (rxfilter) {
                   1491:                sc->sc_ctrl_mac_tbl_uc->nentries = 0;
                   1492:                sc->sc_ctrl_mac_tbl_mc->nentries = nentries;
                   1493:                r = vioif_set_rx_filter(sc);
                   1494:                if (r != 0) {
                   1495:                        rxfilter = 0;
                   1496:                        allmulti = 1; /* fallback */
                   1497:                }
                   1498:        } else {
                   1499:                /* remove rx filter */
                   1500:                sc->sc_ctrl_mac_tbl_uc->nentries = 0;
                   1501:                sc->sc_ctrl_mac_tbl_mc->nentries = 0;
                   1502:                r = vioif_set_rx_filter(sc);
                   1503:                /* what to do on failure? */
                   1504:        }
                   1505:        if (allmulti) {
                   1506:                r = vioif_set_allmulti(sc, true);
                   1507:                if (r != 0) {
                   1508:                        allmulti = 0;
                   1509:                        promisc = 1; /* fallback */
                   1510:                }
                   1511:        } else {
                   1512:                r = vioif_set_allmulti(sc, false);
                   1513:                /* what to do on failure? */
                   1514:        }
                   1515:        if (promisc) {
                   1516:                r = vioif_set_promisc(sc, true);
                   1517:        } else {
                   1518:                r = vioif_set_promisc(sc, false);
                   1519:        }
                   1520:
                   1521:        return r;
                   1522: }
                   1523:
1.34      ozaki-r  1524: static bool
                   1525: vioif_is_link_up(struct vioif_softc *sc)
                   1526: {
                   1527:        struct virtio_softc *vsc = sc->sc_virtio;
                   1528:        uint16_t status;
                   1529:
                   1530:        if (virtio_features(vsc) & VIRTIO_NET_F_STATUS)
                   1531:                status = virtio_read_device_config_2(vsc,
                   1532:                    VIRTIO_NET_CONFIG_STATUS);
                   1533:        else
                   1534:                status = VIRTIO_NET_S_LINK_UP;
                   1535:
                   1536:        return ((status & VIRTIO_NET_S_LINK_UP) != 0);
                   1537: }
                   1538:
                   1539: /* change link status */
                   1540: static void
                   1541: vioif_update_link_status(struct vioif_softc *sc)
                   1542: {
                   1543:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
                   1544:        bool active, changed;
                   1545:        int link;
                   1546:
                   1547:        active = vioif_is_link_up(sc);
                   1548:        changed = false;
                   1549:
                   1550:        VIOIF_TX_LOCK(sc);
                   1551:        if (active) {
                   1552:                if (!sc->sc_link_active)
                   1553:                        changed = true;
                   1554:
                   1555:                link = LINK_STATE_UP;
                   1556:                sc->sc_link_active = true;
                   1557:        } else {
                   1558:                if (sc->sc_link_active)
                   1559:                        changed = true;
                   1560:
                   1561:                link = LINK_STATE_DOWN;
                   1562:                sc->sc_link_active = false;
                   1563:        }
                   1564:        VIOIF_TX_UNLOCK(sc);
                   1565:
                   1566:        if (changed)
                   1567:                if_link_state_change(ifp, link);
                   1568: }
                   1569:
                   1570: static int
                   1571: vioif_config_change(struct virtio_softc *vsc)
                   1572: {
                   1573:        struct vioif_softc *sc = device_private(virtio_child(vsc));
                   1574:
                   1575: #ifdef VIOIF_SOFTINT_INTR
                   1576:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
                   1577: #endif
                   1578:
                   1579: #ifdef VIOIF_SOFTINT_INTR
                   1580:        KASSERT(!cpu_intr_p());
                   1581:        vioif_update_link_status(sc);
                   1582:        vioif_start(ifp);
                   1583: #else
                   1584:        softint_schedule(sc->sc_ctl_softint);
                   1585: #endif
                   1586:
                   1587:        return 0;
                   1588: }
                   1589:
                   1590: static void
                   1591: vioif_ctl_softint(void *arg)
                   1592: {
                   1593:        struct vioif_softc *sc = arg;
                   1594:        struct ifnet *ifp = &sc->sc_ethercom.ec_if;
                   1595:
                   1596:        vioif_update_link_status(sc);
                   1597:        vioif_start(ifp);
                   1598: }
                   1599:
1.26      pgoyette 1600: MODULE(MODULE_CLASS_DRIVER, if_vioif, "virtio");
                   1601:
                   1602: #ifdef _MODULE
                   1603: #include "ioconf.c"
                   1604: #endif
                   1605:
                   1606: static int
                   1607: if_vioif_modcmd(modcmd_t cmd, void *opaque)
                   1608: {
                   1609:        int error = 0;
                   1610:
                   1611: #ifdef _MODULE
                   1612:        switch (cmd) {
                   1613:        case MODULE_CMD_INIT:
                   1614:                error = config_init_component(cfdriver_ioconf_if_vioif,
                   1615:                    cfattach_ioconf_if_vioif, cfdata_ioconf_if_vioif);
                   1616:                break;
                   1617:        case MODULE_CMD_FINI:
                   1618:                error = config_fini_component(cfdriver_ioconf_if_vioif,
                   1619:                    cfattach_ioconf_if_vioif, cfdata_ioconf_if_vioif);
                   1620:                break;
                   1621:        default:
                   1622:                error = ENOTTY;
                   1623:                break;
                   1624:        }
                   1625: #endif
                   1626:
                   1627:        return error;
                   1628: }

CVSweb <webmaster@jp.NetBSD.org>