This fixes up tsleep priorities in vio(4) and makes sleeps
interruptable so that ifconfig can be killed with ^C.  Tested
on qemu with a previous diff that makes vio(4) hang there.

OK?

diff --git sys/dev/pci/if_vio.c sys/dev/pci/if_vio.c
index 97af2a2..d8c9798 100644
--- sys/dev/pci/if_vio.c
+++ sys/dev/pci/if_vio.c
@@ -281,11 +281,11 @@ int       vio_ctrl_rx(struct vio_softc *, int, int);
 int    vio_set_rx_filter(struct vio_softc *);
 void   vio_iff(struct vio_softc *);
 int    vio_media_change(struct ifnet *);
 void   vio_media_status(struct ifnet *, struct ifmediareq *);
 int    vio_ctrleof(struct virtqueue *);
-void   vio_wait_ctrl(struct vio_softc *sc);
+int    vio_wait_ctrl(struct vio_softc *sc);
 int    vio_wait_ctrl_done(struct vio_softc *sc);
 void   vio_ctrl_wakeup(struct vio_softc *, enum vio_ctrl_state);
 int    vio_alloc_mem(struct vio_softc *);
 int    vio_alloc_dmamem(struct vio_softc *);
 void   vio_free_dmamem(struct vio_softc *);
@@ -1219,11 +1219,12 @@ vio_ctrl_rx(struct vio_softc *sc, int cmd, int onoff)
 
        if (vsc->sc_nvqs < 3)
                return ENOTSUP;
 
        splassert(IPL_NET);
-       vio_wait_ctrl(sc);
+       if ((r = vio_wait_ctrl(sc)) != 0)
+               return r;
 
        sc->sc_ctrl_cmd->class = VIRTIO_NET_CTRL_RX;
        sc->sc_ctrl_cmd->command = cmd;
        sc->sc_ctrl_rx->onoff = onoff;
 
@@ -1246,14 +1247,12 @@ vio_ctrl_rx(struct vio_softc *sc, int cmd, int onoff)
            sizeof(*sc->sc_ctrl_rx), 1);
        VIO_DMAMEM_ENQUEUE(sc, vq, slot, sc->sc_ctrl_status,
            sizeof(*sc->sc_ctrl_status), 0);
        virtio_enqueue_commit(vsc, vq, slot, 1);
 
-       if (vio_wait_ctrl_done(sc)) {
-               r = EIO;
+       if ((r = vio_wait_ctrl_done(sc)) != 0)
                goto out;
-       }
 
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_cmd,
            sizeof(*sc->sc_ctrl_cmd), BUS_DMASYNC_POSTWRITE);
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_rx,
            sizeof(*sc->sc_ctrl_rx), BUS_DMASYNC_POSTWRITE);
@@ -1271,28 +1270,38 @@ vio_ctrl_rx(struct vio_softc *sc, int cmd, int onoff)
 out:
        vio_ctrl_wakeup(sc, FREE);
        return r;
 }
 
-void
+int
 vio_wait_ctrl(struct vio_softc *sc)
 {
-       while (sc->sc_ctrl_inuse != FREE)
-               tsleep(&sc->sc_ctrl_inuse, IPL_NET, "vio_wait", 0);
+       int r = 0;
+
+       while (sc->sc_ctrl_inuse != FREE) {
+               r = tsleep(&sc->sc_ctrl_inuse, PRIBIO|PCATCH, "viowait", 0);
+               if (r == EINTR)
+                       return r;
+       }
        sc->sc_ctrl_inuse = INUSE;
+
+       return r;
 }
 
 int
 vio_wait_ctrl_done(struct vio_softc *sc)
 {
        int r = 0;
+
        while (sc->sc_ctrl_inuse != DONE && sc->sc_ctrl_inuse != RESET) {
                if (sc->sc_ctrl_inuse == RESET) {
-                       r = 1;
+                       r = EIO;
                        break;
                }
-               tsleep(&sc->sc_ctrl_inuse, IPL_NET, "vio_wait", 0);
+               r = tsleep(&sc->sc_ctrl_inuse, PRIBIO|PCATCH, "viodone", 0);
+               if (r == EINTR)
+                       break;
        }
        return r;
 }
 
 void
@@ -1334,11 +1343,12 @@ vio_set_rx_filter(struct vio_softc *sc)
        splassert(IPL_NET);
 
        if (vsc->sc_nvqs < 3)
                return ENOTSUP;
 
-       vio_wait_ctrl(sc);
+       if ((r = vio_wait_ctrl(sc)) != 0)
+               return r;
 
        sc->sc_ctrl_cmd->class = VIRTIO_NET_CTRL_MAC;
        sc->sc_ctrl_cmd->command = VIRTIO_NET_CTRL_MAC_TABLE_SET;
 
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_cmd,
@@ -1364,14 +1374,12 @@ vio_set_rx_filter(struct vio_softc *sc)
            sc->sc_ctrl_mac_tbl_mc->nentries * ETHER_ADDR_LEN, 1);
        VIO_DMAMEM_ENQUEUE(sc, vq, slot, sc->sc_ctrl_status,
            sizeof(*sc->sc_ctrl_status), 0);
        virtio_enqueue_commit(vsc, vq, slot, 1);
 
-       if (vio_wait_ctrl_done(sc)) {
-               r = EIO;
+       if ((r = vio_wait_ctrl_done(sc)) != 0)
                goto out;
-       }
 
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_cmd,
            sizeof(*sc->sc_ctrl_cmd), BUS_DMASYNC_POSTWRITE);
        VIO_DMAMEM_SYNC(vsc, sc, sc->sc_ctrl_mac_info,
            VIO_CTRL_MAC_INFO_SIZE, BUS_DMASYNC_POSTWRITE);
@@ -1436,29 +1444,22 @@ vio_iff(struct vio_softc *sc)
 
        /* set unicast address, VirtualBox wants that */
        memcpy(sc->sc_ctrl_mac_tbl_uc->macs[0], ac->ac_enaddr, ETHER_ADDR_LEN);
        sc->sc_ctrl_mac_tbl_uc->nentries = 1;
 
-       if (rxfilter) {
+       if (rxfilter)
                sc->sc_ctrl_mac_tbl_mc->nentries = nentries;
-               r = vio_set_rx_filter(sc);
-               if (r != 0) {
-                       rxfilter = 0;
-                       allmulti = 1; /* fallback */
-               }
-       } else {
-               sc->sc_ctrl_mac_tbl_mc->nentries = 0;
-               vio_set_rx_filter(sc);
-       }
 
-       if (allmulti) {
-               r = vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, 1);
-               if (r != 0) {
-                       allmulti = 0;
-                       promisc = 1; /* fallback */
-               }
-       } else {
-               vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, 0);
-       }
+       r = vio_set_rx_filter(sc);
+       if (r && r != ENOTSUP)
+               return;
+       else if (r == ENOTSUP && rxfilter)
+               allmulti = 1; /* fallback */
+
+       r = vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_ALLMULTI, allmulti);
+       if (r && r != ENOTSUP)
+               return;
+       else if (r == ENOTSUP && allmulti)
+               promisc = 1; /* fallback */
 
        vio_ctrl_rx(sc, VIRTIO_NET_CTRL_RX_PROMISC, promisc);
 }

Reply via email to