Module Name:    src
Committed By:   jmcneill
Date:           Fri Aug 11 18:41:42 UTC 2017

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

Log Message:
Defer sdmmc discard operations to the sdmmc task queue. Fixes a panic
introduced by ld.c r1.102.


To generate a diff of this commit:
cvs rdiff -u -r1.32 -r1.33 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.32 src/sys/dev/sdmmc/ld_sdmmc.c:1.33
--- src/sys/dev/sdmmc/ld_sdmmc.c:1.32	Wed Aug  9 16:44:40 2017
+++ src/sys/dev/sdmmc/ld_sdmmc.c	Fri Aug 11 18:41:42 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: ld_sdmmc.c,v 1.32 2017/08/09 16:44:40 mlelstv Exp $	*/
+/*	$NetBSD: ld_sdmmc.c,v 1.33 2017/08/11 18:41:42 jmcneill Exp $	*/
 
 /*
  * Copyright (c) 2008 KIYOHARA Takashi
@@ -28,7 +28,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.32 2017/08/09 16:44:40 mlelstv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v 1.33 2017/08/11 18:41:42 jmcneill Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_sdmmc.h"
@@ -65,15 +65,24 @@ __KERNEL_RCSID(0, "$NetBSD: ld_sdmmc.c,v
 #define	LD_SDMMC_IORETRIES	5	/* number of retries before giving up */
 #define	RECOVERYTIME		hz/2	/* time to wait before retrying a cmd */
 
+#define	LD_SDMMC_MAXQUEUECNT	4	/* number of queued bio requests */
+#define	LD_SDMMC_MAXTASKCNT	8	/* number of tasks in task pool */
+
 struct ld_sdmmc_softc;
 
 struct ld_sdmmc_task {
 	struct sdmmc_task task;
 
 	struct ld_sdmmc_softc *task_sc;
+
+	/* bio tasks */
 	struct buf *task_bp;
 	int task_retries; /* number of xfer retry */
 	struct callout task_restart_ch;
+
+	/* discard tasks */
+	off_t task_pos;
+	off_t task_len;
 };
 
 struct ld_sdmmc_softc {
@@ -81,9 +90,12 @@ struct ld_sdmmc_softc {
 	int sc_hwunit;
 
 	struct sdmmc_function *sc_sf;
-#define LD_SDMMC_MAXQUEUECNT 4
-	struct ld_sdmmc_task sc_task[LD_SDMMC_MAXQUEUECNT];
+	struct ld_sdmmc_task sc_task[LD_SDMMC_MAXTASKCNT];
 	pcq_t *sc_freeq;
+
+	struct evcnt sc_ev_discard;	/* discard counter */
+	struct evcnt sc_ev_discarderr;	/* discard error counter */
+	struct evcnt sc_ev_discardbusy;	/* discard busy counter */
 };
 
 static int ld_sdmmc_match(device_t, cfdata_t, void *);
@@ -98,6 +110,7 @@ static int ld_sdmmc_ioctl(struct ld_soft
 
 static void ld_sdmmc_doattach(void *);
 static void ld_sdmmc_dobio(void *);
+static void ld_sdmmc_dodiscard(void *);
 
 CFATTACH_DECL_NEW(ld_sdmmc, sizeof(struct ld_sdmmc_softc),
     ld_sdmmc_match, ld_sdmmc_attach, ld_sdmmc_detach, NULL);
@@ -132,6 +145,13 @@ ld_sdmmc_attach(device_t parent, device_
 	    sa->sf->cid.rev, sa->sf->cid.psn, sa->sf->cid.mdt);
 	aprint_naive("\n");
 
+	evcnt_attach_dynamic(&sc->sc_ev_discard, EVCNT_TYPE_MISC,
+	    NULL, device_xname(self), "sdmmc discard count");
+	evcnt_attach_dynamic(&sc->sc_ev_discarderr, EVCNT_TYPE_MISC,
+	    NULL, device_xname(self), "sdmmc discard errors");
+	evcnt_attach_dynamic(&sc->sc_ev_discardbusy, EVCNT_TYPE_MISC,
+	    NULL, device_xname(self), "sdmmc discard busy");
+
 	const int ntask = __arraycount(sc->sc_task);
 	sc->sc_freeq = pcq_create(ntask, KM_SLEEP);
 	for (i = 0; i < ntask; i++) {
@@ -213,6 +233,9 @@ ld_sdmmc_detach(device_t dev, int flags)
 		callout_destroy(&sc->sc_task[i].task_restart_ch);
 
 	pcq_destroy(sc->sc_freeq);
+	evcnt_detach(&sc->sc_ev_discard);
+	evcnt_detach(&sc->sc_ev_discarderr);
+	evcnt_detach(&sc->sc_ev_discardbusy);
 
 	return 0;
 }
@@ -314,12 +337,44 @@ ld_sdmmc_dump(struct ld_softc *ld, void 
 	    blkcnt * ld->sc_secsize);
 }
 
+static void
+ld_sdmmc_dodiscard(void *arg)
+{
+	struct ld_sdmmc_task *task = arg;
+	struct ld_sdmmc_softc *sc = task->task_sc;
+	const off_t pos = task->task_pos;
+	const off_t len = task->task_len;
+	int error;
+
+	/* An error from discard is non-fatal */
+	error = sdmmc_mem_discard(sc->sc_sf, pos, len);
+	if (error != 0)
+		sc->sc_ev_discarderr.ev_count++;
+	else
+		sc->sc_ev_discard.ev_count++;
+
+	pcq_put(sc->sc_freeq, task);
+}
+
 static int
 ld_sdmmc_discard(struct ld_softc *ld, off_t pos, off_t len)
 {
 	struct ld_sdmmc_softc *sc = device_private(ld->sc_dv);
+	struct ld_sdmmc_task *task = pcq_get(sc->sc_freeq);
+
+	if (task == NULL) {
+		sc->sc_ev_discardbusy.ev_count++;
+		return 0;
+	}
 
-	return sdmmc_mem_discard(sc->sc_sf, pos, len);
+	task->task_pos = pos;
+	task->task_len = len;
+
+	sdmmc_init_task(&task->task, ld_sdmmc_dodiscard, task);
+
+	sdmmc_add_task(sc->sc_sf->sc, &task->task);
+
+	return 0;
 }
 
 static int

Reply via email to