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);
}