svn commit: r290131 - head/sys/dev/ioat
Conrad E. Meyer
cem at FreeBSD.org
Thu Oct 29 04:16:41 UTC 2015
Author: cem
Date: Thu Oct 29 04:16:39 2015
New Revision: 290131
URL: https://svnweb.freebsd.org/changeset/base/290131
Log:
ioat: Drain/quiesce the device less racily
On detach and during a forced HW reset.
Sponsored by: EMC / Isilon Storage Division
Modified:
head/sys/dev/ioat/ioat.c
head/sys/dev/ioat/ioat_internal.h
Modified: head/sys/dev/ioat/ioat.c
==============================================================================
--- head/sys/dev/ioat/ioat.c Thu Oct 29 04:16:28 2015 (r290130)
+++ head/sys/dev/ioat/ioat.c Thu Oct 29 04:16:39 2015 (r290131)
@@ -96,7 +96,7 @@ static inline struct ioat_softc *ioat_ge
static inline void ioat_put(struct ioat_softc *, enum ioat_ref_kind);
static inline void ioat_putn(struct ioat_softc *, uint32_t,
enum ioat_ref_kind);
-static void ioat_drain(struct ioat_softc *);
+static void ioat_drain_locked(struct ioat_softc *);
#define ioat_log_message(v, ...) do { \
if ((v) <= g_ioat_debug_level) { \
@@ -271,6 +271,7 @@ ioat_attach(device_t device)
ioat_process_events(ioat);
ioat_setup_sysctl(device);
+ ioat->chan_idx = ioat_channel_index;
ioat_channel[ioat_channel_index++] = ioat;
ioat_test_attach();
@@ -288,7 +289,13 @@ ioat_detach(device_t device)
ioat = DEVICE2SOFTC(device);
ioat_test_detach();
- ioat_drain(ioat);
+
+ mtx_lock(IOAT_REFLK);
+ ioat->quiescing = TRUE;
+ ioat_channel[ioat->chan_idx] = NULL;
+
+ ioat_drain_locked(ioat);
+ mtx_unlock(IOAT_REFLK);
ioat_teardown_intr(ioat);
callout_drain(&ioat->timer);
@@ -614,10 +621,16 @@ out:
bus_dmaengine_t
ioat_get_dmaengine(uint32_t index)
{
+ struct ioat_softc *sc;
if (index >= ioat_channel_index)
return (NULL);
- return (&ioat_get(ioat_channel[index], IOAT_DMAENGINE_REF)->dmaengine);
+
+ sc = ioat_channel[index];
+ if (sc == NULL || sc->quiescing)
+ return (NULL);
+
+ return (&ioat_get(sc, IOAT_DMAENGINE_REF)->dmaengine);
}
void
@@ -887,6 +900,10 @@ ioat_reserve_space(struct ioat_softc *io
error = EINVAL;
goto out;
}
+ if (ioat->quiescing) {
+ error = ENXIO;
+ goto out;
+ }
for (;;) {
if (ioat_get_ring_space(ioat) >= num_descs)
@@ -1238,6 +1255,12 @@ ioat_reset_hw(struct ioat_softc *ioat)
uint64_t status;
uint32_t chanerr;
unsigned timeout;
+ int error;
+
+ mtx_lock(IOAT_REFLK);
+ ioat->quiescing = TRUE;
+ ioat_drain_locked(ioat);
+ mtx_unlock(IOAT_REFLK);
status = ioat_get_chansts(ioat);
if (is_ioat_active(status) || is_ioat_idle(status))
@@ -1249,8 +1272,10 @@ ioat_reset_hw(struct ioat_softc *ioat)
DELAY(1000);
status = ioat_get_chansts(ioat);
}
- if (timeout == 20)
- return (ETIMEDOUT);
+ if (timeout == 20) {
+ error = ETIMEDOUT;
+ goto out;
+ }
KASSERT(ioat_get_active(ioat) == 0, ("active after quiesce"));
@@ -1280,8 +1305,10 @@ ioat_reset_hw(struct ioat_softc *ioat)
/* Wait at most 20 ms */
for (timeout = 0; ioat_reset_pending(ioat) && timeout < 20; timeout++)
DELAY(1000);
- if (timeout == 20)
- return (ETIMEDOUT);
+ if (timeout == 20) {
+ error = ETIMEDOUT;
+ goto out;
+ }
if (ioat_model_resets_msix(ioat)) {
ioat_log_message(1, "device resets registers; restored\n");
@@ -1294,13 +1321,16 @@ ioat_reset_hw(struct ioat_softc *ioat)
/* So this really shouldn't happen... */
ioat_log_message(0, "Device is active after a reset?\n");
ioat_write_chanctrl(ioat, IOAT_CHANCTRL_RUN);
- return (0);
+ error = 0;
+ goto out;
}
chanerr = ioat_read_4(ioat, IOAT_CHANERR_OFFSET);
ioat_halted_debug(ioat, chanerr);
- if (chanerr != 0)
- return (EIO);
+ if (chanerr != 0) {
+ error = EIO;
+ goto out;
+ }
/*
* Bring device back online after reset. Writing CHAINADDR brings the
@@ -1315,7 +1345,17 @@ ioat_reset_hw(struct ioat_softc *ioat)
ioat_write_chanctrl(ioat, IOAT_CHANCTRL_RUN);
ioat_write_chancmp(ioat, ioat->comp_update_bus_addr);
ioat_write_chainaddr(ioat, ioat->ring[0]->hw_desc_bus_addr);
- return (ioat_start_channel(ioat));
+ error = 0;
+
+out:
+ mtx_lock(IOAT_REFLK);
+ ioat->quiescing = FALSE;
+ mtx_unlock(IOAT_REFLK);
+
+ if (error == 0)
+ error = ioat_start_channel(ioat);
+
+ return (error);
}
static int
@@ -1456,11 +1496,10 @@ ioat_put(struct ioat_softc *ioat, enum i
}
static void
-ioat_drain(struct ioat_softc *ioat)
+ioat_drain_locked(struct ioat_softc *ioat)
{
- mtx_lock(IOAT_REFLK);
+ mtx_assert(IOAT_REFLK, MA_OWNED);
while (ioat->refcnt > 0)
msleep(IOAT_REFLK, IOAT_REFLK, 0, "ioat_drain", 0);
- mtx_unlock(IOAT_REFLK);
}
Modified: head/sys/dev/ioat/ioat_internal.h
==============================================================================
--- head/sys/dev/ioat/ioat_internal.h Thu Oct 29 04:16:28 2015 (r290130)
+++ head/sys/dev/ioat/ioat_internal.h Thu Oct 29 04:16:39 2015 (r290131)
@@ -365,6 +365,7 @@ struct ioat_softc {
})
int version;
+ int chan_idx;
struct mtx submit_lock;
device_t device;
@@ -389,6 +390,7 @@ struct ioat_softc {
struct callout timer;
+ boolean_t quiescing;
boolean_t is_resize_pending;
boolean_t is_completion_pending;
boolean_t is_reset_pending;
More information about the svn-src-all
mailing list