summaryrefslogtreecommitdiff
path: root/sys/dev/sdmmc
diff options
context:
space:
mode:
authorjmcneill <jmcneill@NetBSD.org>2018-11-09 14:39:19 +0000
committerjmcneill <jmcneill@NetBSD.org>2018-11-09 14:39:19 +0000
commitc36d815fb2dd7ded5cccfeffd188d685fd75a13b (patch)
tree329ff1663031c30a393db2f98538b5800425fc4f /sys/dev/sdmmc
parent742fec1253aa73a88208bafa0e549ff4ac9618ed (diff)
Defer DIOCCACHESYNC to the sdmmc task queue so they are serialized with other requests.
Diffstat (limited to 'sys/dev/sdmmc')
-rw-r--r--sys/dev/sdmmc/ld_sdmmc.c62
1 files changed, 57 insertions, 5 deletions
diff --git a/sys/dev/sdmmc/ld_sdmmc.c b/sys/dev/sdmmc/ld_sdmmc.c
index e6367d479a1..fb56783048e 100644
--- a/sys/dev/sdmmc/ld_sdmmc.c
+++ b/sys/dev/sdmmc/ld_sdmmc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: ld_sdmmc.c,v 1.34 2017/08/20 15:58:43 mlelstv Exp $ */
+/* $NetBSD: ld_sdmmc.c,v 1.35 2018/11/09 14:39:19 jmcneill Exp $ */
/*
* Copyright (c) 2008 KIYOHARA Takashi
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.34 2017/08/20 15:58:43 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.35 2018/11/09 14:39:19 jmcneill Exp $");
#ifdef _KERNEL_OPT
#include "opt_sdmmc.h"
@@ -78,6 +78,11 @@ struct ld_sdmmc_task {
struct buf *task_bp;
int task_retries; /* number of xfer retry */
struct callout task_restart_ch;
+
+ kmutex_t task_lock;
+ kcondvar_t task_cv;
+
+ uintptr_t task_data;
};
struct ld_sdmmc_softc {
@@ -91,6 +96,7 @@ struct ld_sdmmc_softc {
struct evcnt sc_ev_discard; /* discard counter */
struct evcnt sc_ev_discarderr; /* discard error counter */
struct evcnt sc_ev_discardbusy; /* discard busy counter */
+ struct evcnt sc_ev_cachesyncbusy; /* cache sync busy counter */
};
static int ld_sdmmc_match(device_t, cfdata_t, void *);
@@ -153,6 +159,8 @@ ld_sdmmc_attach(device_t parent, device_t self, void *aux)
task = &sc->sc_task[i];
task->task_sc = sc;
callout_init(&task->task_restart_ch, CALLOUT_MPSAFE);
+ mutex_init(&task->task_lock, MUTEX_DEFAULT, IPL_NONE);
+ cv_init(&task->task_cv, "ldsdmmctask");
pcq_put(sc->sc_freeq, task);
}
@@ -224,8 +232,11 @@ ld_sdmmc_detach(device_t dev, int flags)
return rv;
ldenddetach(ld);
- for (i = 0; i < __arraycount(sc->sc_task); i++)
+ for (i = 0; i < __arraycount(sc->sc_task); i++) {
callout_destroy(&sc->sc_task[i].task_restart_ch);
+ mutex_destroy(&sc->sc_task[i].task_lock);
+ cv_destroy(&sc->sc_task[i].task_cv);
+ }
pcq_destroy(sc->sc_freeq);
evcnt_detach(&sc->sc_ev_discard);
@@ -379,15 +390,56 @@ ld_sdmmc_discard(struct ld_softc *ld, struct buf *bp)
return 0;
}
+static void
+ld_sdmmc_docachesync(void *arg)
+{
+ struct ld_sdmmc_task *task = arg;
+ struct ld_sdmmc_softc *sc = task->task_sc;
+ const bool poll = (bool)task->task_data;
+
+ task->task_data = sdmmc_mem_flush_cache(sc->sc_sf, poll);
+
+ mutex_enter(&task->task_lock);
+ cv_signal(&task->task_cv);
+ mutex_exit(&task->task_lock);
+}
+
+static int
+ld_sdmmc_cachesync(struct ld_softc *ld, bool poll)
+{
+ struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
+ struct ld_sdmmc_task *task = pcq_get(sc->sc_freeq);
+ int error = 0;
+
+ if (task == NULL) {
+ sc->sc_ev_cachesyncbusy.ev_count++;
+ return EBUSY;
+ }
+
+ sdmmc_init_task(&task->task, ld_sdmmc_docachesync, task);
+ task->task_data = poll;
+
+ mutex_enter(&task->task_lock);
+ sdmmc_add_task(sc->sc_sf->sc, &task->task);
+ error = cv_wait_sig(&task->task_cv, &task->task_lock);
+ mutex_exit(&task->task_lock);
+
+ if (error == 0)
+ error = (int)task->task_data;
+
+ pcq_put(sc->sc_freeq, task);
+
+ return error;
+}
+
static int
ld_sdmmc_ioctl(struct ld_softc *ld, u_long cmd, void *addr, int32_t flag,
bool poll)
{
- struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
switch (cmd) {
case DIOCCACHESYNC:
- return sdmmc_mem_flush_cache(sc->sc_sf, poll);
+ return ld_sdmmc_cachesync(ld, poll);
default:
return EPASSTHROUGH;
}