summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorDavid Gwynne <dlg@cvs.openbsd.org>2019-02-26 03:12:35 +0000
committerDavid Gwynne <dlg@cvs.openbsd.org>2019-02-26 03:12:35 +0000
commit9b017df4d1a31f9821ba7b6c61b8c1ed914d6ab3 (patch)
treedca9380327b88d013e395a463270fd820a1a21b6 /sys/dev
parent2f46e8027061a2063fac0d8dcf7e50e572f7484c (diff)
avoid a deadlock in ixl_down when calling ifq_barrier.
this is particularly noticable on sparc64 when you reboot. ok jmatthew@
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/if_ixl.c41
1 files changed, 32 insertions, 9 deletions
diff --git a/sys/dev/pci/if_ixl.c b/sys/dev/pci/if_ixl.c
index 4a04eca2220..b9cab5cf297 100644
--- a/sys/dev/pci/if_ixl.c
+++ b/sys/dev/pci/if_ixl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: if_ixl.c,v 1.20 2019/02/24 22:49:31 dlg Exp $ */
+/* $OpenBSD: if_ixl.c,v 1.21 2019/02/26 03:12:34 dlg Exp $ */
/*
* Copyright (c) 2013-2015, Intel Corporation
@@ -60,6 +60,7 @@
#include <sys/queue.h>
#include <sys/timeout.h>
#include <sys/task.h>
+#include <sys/syslog.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -1120,6 +1121,9 @@ struct ixl_softc {
unsigned int sc_tx_ring_ndescs;
unsigned int sc_rx_ring_ndescs;
unsigned int sc_nqueues; /* 1 << sc_nqueues */
+
+ struct rwlock sc_cfg_lock;
+ unsigned int sc_dead;
};
#define DEVNAME(_sc) ((_sc)->sc_dev.dv_xname)
@@ -1379,6 +1383,8 @@ ixl_attach(struct device *parent, struct device *self, void *aux)
uint64_t phy_types = 0;
int tries;
+ rw_init(&sc->sc_cfg_lock, "ixlcfg");
+
sc->sc_pc = pa->pa_pc;
sc->sc_tag = pa->pa_tag;
sc->sc_dmat = pa->pa_dmat;
@@ -1813,6 +1819,12 @@ ixl_up(struct ixl_softc *sc)
nqueues = ixl_nqueues(sc);
KASSERT(nqueues == 1); /* XXX */
+ rw_enter_write(&sc->sc_cfg_lock);
+ if (sc->sc_dead) {
+ rw_exit_write(&sc->sc_cfg_lock);
+ return (ENXIO);
+ }
+
/* allocation is the only thing that can fail, so do it up front */
for (i = 0; i < nqueues; i++) {
rxr = ixl_rxr_alloc(sc, i);
@@ -1892,6 +1904,8 @@ ixl_up(struct ixl_softc *sc)
ixl_wr(sc, I40E_PFINT_ITR0(1), 0x7a);
ixl_wr(sc, I40E_PFINT_ITR0(2), 0);
+ rw_exit_write(&sc->sc_cfg_lock);
+
return (ENETRESET);
free:
@@ -1910,8 +1924,10 @@ free:
ixl_txr_free(sc, txr);
ixl_rxr_free(sc, rxr);
}
+ rw_exit_write(&sc->sc_cfg_lock);
return (rv);
down:
+ rw_exit_write(&sc->sc_cfg_lock);
ixl_down(sc);
return (ETIMEDOUT);
}
@@ -1967,8 +1983,12 @@ ixl_down(struct ixl_softc *sc)
nqueues = ixl_nqueues(sc);
+ rw_enter_write(&sc->sc_cfg_lock);
+
CLR(ifp->if_flags, IFF_RUNNING);
+ NET_UNLOCK();
+
/* mask interrupts */
reg = ixl_rd(sc, I40E_QINT_RQCTL(I40E_INTR_NOTX_QUEUE));
CLR(reg, I40E_QINT_RQCTL_CAUSE_ENA_MASK);
@@ -2016,15 +2036,10 @@ ixl_down(struct ixl_softc *sc)
txr = ifp->if_ifqs[i]->ifq_softc;
if (ixl_txr_disabled(sc, txr) != 0)
- error = ETIMEDOUT;
+ goto die;
if (ixl_rxr_disabled(sc, rxr) != 0)
- error = ETIMEDOUT;
- }
-
- if (error) {
- printf("%s: failed to shut down rings\n", DEVNAME(sc));
- return (error);
+ goto die;
}
for (i = 0; i < nqueues; i++) {
@@ -2044,7 +2059,15 @@ ixl_down(struct ixl_softc *sc)
ifp->if_ifqs[i]->ifq_softc = NULL;
}
- return (0);
+out:
+ rw_exit_write(&sc->sc_cfg_lock);
+ NET_LOCK();
+ return (error);
+die:
+ sc->sc_dead = 1;
+ log(LOG_CRIT, "%s: failed to shut down rings", DEVNAME(sc));
+ error = ETIMEDOUT;
+ goto out;
}
static struct ixl_tx_ring *