Module Name: src Committed By: ozaki-r Date: Tue Mar 28 04:10:33 UTC 2017
Modified Files: src/sys/dev/pci: if_vioif.c virtio.c Log Message: Handle config change interrupts to inhibit sending packets while link down PR kern/52103 by s-yamaguchi@IIJ To generate a diff of this commit: cvs rdiff -u -r1.33 -r1.34 src/sys/dev/pci/if_vioif.c cvs rdiff -u -r1.26 -r1.27 src/sys/dev/pci/virtio.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/pci/if_vioif.c diff -u src/sys/dev/pci/if_vioif.c:1.33 src/sys/dev/pci/if_vioif.c:1.34 --- src/sys/dev/pci/if_vioif.c:1.33 Tue Mar 28 04:09:52 2017 +++ src/sys/dev/pci/if_vioif.c Tue Mar 28 04:10:33 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: if_vioif.c,v 1.33 2017/03/28 04:09:52 ozaki-r Exp $ */ +/* $NetBSD: if_vioif.c,v 1.34 2017/03/28 04:10:33 ozaki-r Exp $ */ /* * Copyright (c) 2010 Minoura Makoto. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.33 2017/03/28 04:09:52 ozaki-r Exp $"); +__KERNEL_RCSID(0, "$NetBSD: if_vioif.c,v 1.34 2017/03/28 04:10:33 ozaki-r Exp $"); #ifdef _KERNEL_OPT #include "opt_net_mpsafe.h" @@ -190,6 +190,7 @@ struct vioif_softc { uint8_t sc_mac[ETHER_ADDR_LEN]; struct ethercom sc_ethercom; short sc_deferred_init_done; + bool sc_link_active; /* bus_dmamem */ bus_dma_segment_t sc_hdr_segs[1]; @@ -218,6 +219,7 @@ struct vioif_softc { bus_dmamap_t sc_ctrl_tbl_mc_dmamap; void *sc_rx_softint; + void *sc_ctl_softint; enum { FREE, INUSE, DONE @@ -269,12 +271,16 @@ static int vioif_tx_vq_done_locked(struc static void vioif_tx_drain(struct vioif_softc *); /* other control */ +static bool vioif_is_link_up(struct vioif_softc *); +static void vioif_update_link_status(struct vioif_softc *); static int vioif_ctrl_rx(struct vioif_softc *, int, bool); static int vioif_set_promisc(struct vioif_softc *, bool); static int vioif_set_allmulti(struct vioif_softc *, bool); static int vioif_set_rx_filter(struct vioif_softc *); static int vioif_rx_filter(struct vioif_softc *); static int vioif_ctrl_vq_done(struct virtqueue *); +static int vioif_config_change(struct virtio_softc *); +static void vioif_ctl_softint(void *); CFATTACH_DECL_NEW(vioif, sizeof(struct vioif_softc), vioif_match, vioif_attach, NULL, NULL); @@ -524,6 +530,7 @@ vioif_attach(device_t parent, device_t s sc->sc_dev = self; sc->sc_virtio = vsc; + sc->sc_link_active = false; req_flags = 0; @@ -536,7 +543,7 @@ vioif_attach(device_t parent, device_t s req_flags |= VIRTIO_F_PCI_INTR_MSIX; virtio_child_attach_start(vsc, self, IPL_NET, sc->sc_vq, - NULL, virtio_vq_intr, req_flags, + vioif_config_change, virtio_vq_intr, req_flags, (VIRTIO_NET_F_MAC | VIRTIO_NET_F_STATUS | VIRTIO_NET_F_CTRL_VQ | VIRTIO_NET_F_CTRL_RX | VIRTIO_F_NOTIFY_ON_EMPTY), VIRTIO_NET_FLAG_BITS); @@ -648,7 +655,13 @@ skip: #endif sc->sc_rx_softint = softint_establish(flags, vioif_rx_softint, sc); if (sc->sc_rx_softint == NULL) { - aprint_error_dev(self, "cannot establish softint\n"); + aprint_error_dev(self, "cannot establish rx softint\n"); + goto err; + } + + sc->sc_ctl_softint = softint_establish(flags, vioif_ctl_softint, sc); + if (sc->sc_ctl_softint == NULL) { + aprint_error_dev(self, "cannot establish ctl softint\n"); goto err; } @@ -741,6 +754,7 @@ vioif_init(struct ifnet *ifp) vioif_populate_rx_mbufs(sc); + vioif_update_link_status(sc); ifp->if_flags |= IFF_RUNNING; ifp->if_flags &= ~IFF_OACTIVE; vioif_rx_filter(sc); @@ -772,6 +786,7 @@ vioif_stop(struct ifnet *ifp, int disabl vioif_rx_deq(sc); vioif_tx_drain(sc); ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); + sc->sc_link_active = false; if (disable) vioif_rx_drain(sc); @@ -788,7 +803,8 @@ vioif_start(struct ifnet *ifp) VIOIF_TX_LOCK(sc); - if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING) + if ((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != IFF_RUNNING || + !sc->sc_link_active) goto out; if (sc->sc_stopping) @@ -1503,6 +1519,82 @@ set: return r; } +static bool +vioif_is_link_up(struct vioif_softc *sc) +{ + struct virtio_softc *vsc = sc->sc_virtio; + uint16_t status; + + if (virtio_features(vsc) & VIRTIO_NET_F_STATUS) + status = virtio_read_device_config_2(vsc, + VIRTIO_NET_CONFIG_STATUS); + else + status = VIRTIO_NET_S_LINK_UP; + + return ((status & VIRTIO_NET_S_LINK_UP) != 0); +} + +/* change link status */ +static void +vioif_update_link_status(struct vioif_softc *sc) +{ + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + bool active, changed; + int link; + + active = vioif_is_link_up(sc); + changed = false; + + VIOIF_TX_LOCK(sc); + if (active) { + if (!sc->sc_link_active) + changed = true; + + link = LINK_STATE_UP; + sc->sc_link_active = true; + } else { + if (sc->sc_link_active) + changed = true; + + link = LINK_STATE_DOWN; + sc->sc_link_active = false; + } + VIOIF_TX_UNLOCK(sc); + + if (changed) + if_link_state_change(ifp, link); +} + +static int +vioif_config_change(struct virtio_softc *vsc) +{ + struct vioif_softc *sc = device_private(virtio_child(vsc)); + +#ifdef VIOIF_SOFTINT_INTR + struct ifnet *ifp = &sc->sc_ethercom.ec_if; +#endif + +#ifdef VIOIF_SOFTINT_INTR + KASSERT(!cpu_intr_p()); + vioif_update_link_status(sc); + vioif_start(ifp); +#else + softint_schedule(sc->sc_ctl_softint); +#endif + + return 0; +} + +static void +vioif_ctl_softint(void *arg) +{ + struct vioif_softc *sc = arg; + struct ifnet *ifp = &sc->sc_ethercom.ec_if; + + vioif_update_link_status(sc); + vioif_start(ifp); +} + MODULE(MODULE_CLASS_DRIVER, if_vioif, "virtio"); #ifdef _MODULE Index: src/sys/dev/pci/virtio.c diff -u src/sys/dev/pci/virtio.c:1.26 src/sys/dev/pci/virtio.c:1.27 --- src/sys/dev/pci/virtio.c:1.26 Sun Mar 26 16:53:36 2017 +++ src/sys/dev/pci/virtio.c Tue Mar 28 04:10:33 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: virtio.c,v 1.26 2017/03/26 16:53:36 jdolecek Exp $ */ +/* $NetBSD: virtio.c,v 1.27 2017/03/28 04:10:33 ozaki-r Exp $ */ /* * Copyright (c) 2010 Minoura Makoto. @@ -26,7 +26,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.26 2017/03/26 16:53:36 jdolecek Exp $"); +__KERNEL_RCSID(0, "$NetBSD: virtio.c,v 1.27 2017/03/28 04:10:33 ozaki-r Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -720,10 +720,11 @@ static int virtio_msix_config_intr(void *arg) { struct virtio_softc *sc = arg; + int r = 0; - /* TODO: handle events */ - aprint_debug_dev(sc->sc_dev, "%s\n", __func__); - return 1; + if (sc->sc_config_change != NULL) + r = (sc->sc_config_change)(sc); + return r; } static void