Module Name:    src
Committed By:   jmcneill
Date:           Fri Nov  9 14:39:20 UTC 2018

Modified Files:
        src/sys/dev/sdmmc: ld_sdmmc.c

Log Message:
Defer DIOCCACHESYNC to the sdmmc task queue so they are serialized with other 
requests.


To generate a diff of this commit:
cvs rdiff -u -r1.34 -r1.35 src/sys/dev/sdmmc/ld_sdmmc.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/dev/sdmmc/ld_sdmmc.c
diff -u src/sys/dev/sdmmc/ld_sdmmc.c:1.34 src/sys/dev/sdmmc/ld_sdmmc.c:1.35
--- src/sys/dev/sdmmc/ld_sdmmc.c:1.34	Sun Aug 20 15:58:43 2017
+++ src/sys/dev/sdmmc/ld_sdmmc.c	Fri Nov  9 14:39:19 2018
@@ -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_
 		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, st
 	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;
 	}

Reply via email to