From 0ff814e85443f21ca752d25a481139db3b300b0e Mon Sep 17 00:00:00 2001 From: Conrad Meyer Date: Sat, 9 Apr 2016 13:15:34 +0000 Subject: [PATCH] ioat(4): ioat_get_dmaengine(): Add M_WAITOK mode Sponsored by: EMC / Isilon Storage Division --- sys/dev/ioat/ioat.c | 36 +++++++++++++++++++++++++++++++----- sys/dev/ioat/ioat.h | 4 +++- sys/dev/ioat/ioat_internal.h | 1 + sys/dev/ioat/ioat_test.c | 2 +- 4 files changed, 36 insertions(+), 7 deletions(-) diff --git a/sys/dev/ioat/ioat.c b/sys/dev/ioat/ioat.c index bcc4e9a4658..85ceacb6cbc 100644 --- a/sys/dev/ioat/ioat.c +++ b/sys/dev/ioat/ioat.c @@ -314,6 +314,9 @@ ioat_detach(device_t device) mtx_lock(IOAT_REFLK); ioat->quiescing = TRUE; + ioat->destroying = TRUE; + wakeup(&ioat->quiescing); + ioat_channel[ioat->chan_idx] = NULL; ioat_drain_locked(ioat); @@ -739,18 +742,40 @@ ioat_reset_hw_task(void *ctx, int pending __unused) * User API functions */ bus_dmaengine_t -ioat_get_dmaengine(uint32_t index) +ioat_get_dmaengine(uint32_t index, int flags) { - struct ioat_softc *sc; + struct ioat_softc *ioat; + + KASSERT((flags & ~(M_NOWAIT | M_WAITOK)) == 0, + ("invalid flags: 0x%08x", flags)); + KASSERT((flags & (M_NOWAIT | M_WAITOK)) != (M_NOWAIT | M_WAITOK), + ("invalid wait | nowait")); if (index >= ioat_channel_index) return (NULL); - sc = ioat_channel[index]; - if (sc == NULL || sc->quiescing) + ioat = ioat_channel[index]; + if (ioat == NULL || ioat->destroying) return (NULL); - return (&ioat_get(sc, IOAT_DMAENGINE_REF)->dmaengine); + if (ioat->quiescing) { + if ((flags & M_NOWAIT) != 0) + return (NULL); + + mtx_lock(IOAT_REFLK); + while (ioat->quiescing && !ioat->destroying) + msleep(&ioat->quiescing, IOAT_REFLK, 0, "getdma", 0); + mtx_unlock(IOAT_REFLK); + + if (ioat->destroying) + return (NULL); + } + + /* + * There's a race here between the quiescing check and HW reset or + * module destroy. + */ + return (&ioat_get(ioat, IOAT_DMAENGINE_REF)->dmaengine); } void @@ -1571,6 +1596,7 @@ ioat_reset_hw(struct ioat_softc *ioat) out: mtx_lock(IOAT_REFLK); ioat->quiescing = FALSE; + wakeup(&ioat->quiescing); mtx_unlock(IOAT_REFLK); if (error == 0) diff --git a/sys/dev/ioat/ioat.h b/sys/dev/ioat/ioat.h index 3b6e0946ac1..ff056021773 100644 --- a/sys/dev/ioat/ioat.h +++ b/sys/dev/ioat/ioat.h @@ -68,8 +68,10 @@ typedef void (*bus_dmaengine_callback_t)(void *arg, int error); /* * Called first to acquire a reference to the DMA channel + * + * Flags may be M_WAITOK or M_NOWAIT. */ -bus_dmaengine_t ioat_get_dmaengine(uint32_t channel_index); +bus_dmaengine_t ioat_get_dmaengine(uint32_t channel_index, int flags); /* Release the DMA channel */ void ioat_put_dmaengine(bus_dmaengine_t dmaengine); diff --git a/sys/dev/ioat/ioat_internal.h b/sys/dev/ioat/ioat_internal.h index b33faea05fa..85b7316c92f 100644 --- a/sys/dev/ioat/ioat_internal.h +++ b/sys/dev/ioat/ioat_internal.h @@ -410,6 +410,7 @@ struct ioat_softc { struct task reset_task; boolean_t quiescing; + boolean_t destroying; boolean_t is_resize_pending; boolean_t is_completion_pending; boolean_t is_reset_pending; diff --git a/sys/dev/ioat/ioat_test.c b/sys/dev/ioat/ioat_test.c index ee014c09627..7fecd489418 100644 --- a/sys/dev/ioat/ioat_test.c +++ b/sys/dev/ioat/ioat_test.c @@ -388,7 +388,7 @@ ioat_dma_test(void *arg) return; } - dmaengine = ioat_get_dmaengine(test->channel_index); + dmaengine = ioat_get_dmaengine(test->channel_index, M_NOWAIT); if (dmaengine == NULL) { ioat_test_log(0, "Couldn't acquire dmaengine\n"); test->status[IOAT_TEST_NO_DMA_ENGINE]++;