Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 11 Dec 2019 18:50:23 +0000 (UTC)
From:      Emmanuel Vadot <manu@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r355627 - head/sys/dev/mmc/host
Message-ID:  <201912111850.xBBIoNDT020038@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: manu
Date: Wed Dec 11 18:50:23 2019
New Revision: 355627
URL: https://svnweb.freebsd.org/changeset/base/355627

Log:
  dwmmc: Handle the card detect interrupt
  
  The driver used to always add the mmc device as it's child even
  it no card was detected. Add a function that will detect if the
  card is present or not and that will attach/detach the mmc device.
  The function is either call on attach (as we won't have the interrupt
  fired) or from two taskqueues. The first taskqueue will directly call
  the function when the sdcard was present and is now removed and the other
  one will delay a bit the attach when we didn't had a card and now have one.
  This is mostly based on comments from the sdhci driver where it describe
  a situation when the CD pin is detected before the others pins are connected.
  
  MFC after:	1 month

Modified:
  head/sys/dev/mmc/host/dwmmc.c
  head/sys/dev/mmc/host/dwmmc_altera.c
  head/sys/dev/mmc/host/dwmmc_hisi.c
  head/sys/dev/mmc/host/dwmmc_rockchip.c
  head/sys/dev/mmc/host/dwmmc_samsung.c
  head/sys/dev/mmc/host/dwmmc_var.h

Modified: head/sys/dev/mmc/host/dwmmc.c
==============================================================================
--- head/sys/dev/mmc/host/dwmmc.c	Wed Dec 11 18:43:39 2019	(r355626)
+++ head/sys/dev/mmc/host/dwmmc.c	Wed Dec 11 18:50:23 2019	(r355627)
@@ -45,6 +45,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/malloc.h>
 #include <sys/mutex.h>
 #include <sys/rman.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
 
 #include <dev/mmc/bridge.h>
 #include <dev/mmc/mmcbrvar.h>
@@ -127,6 +129,7 @@ static int dma_done(struct dwmmc_softc *, struct mmc_c
 static int dma_stop(struct dwmmc_softc *);
 static void pio_read(struct dwmmc_softc *, struct mmc_command *);
 static void pio_write(struct dwmmc_softc *, struct mmc_command *);
+static void dwmmc_handle_card_present(struct dwmmc_softc *sc, bool is_present);
 
 static struct resource_spec dwmmc_spec[] = {
 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
@@ -374,7 +377,8 @@ dwmmc_intr(void *arg)
 			sc->dto_rcvd = 1;
 
 		if (reg & SDMMC_INTMASK_CD) {
-			/* XXX: Handle card detect */
+			dwmmc_handle_card_present(sc,
+			    READ4(sc, SDMMC_CDETECT) == 0 ? true : false);
 		}
 	}
 
@@ -407,6 +411,56 @@ dwmmc_intr(void *arg)
 	DWMMC_UNLOCK(sc);
 }
 
+static void
+dwmmc_handle_card_present(struct dwmmc_softc *sc, bool is_present)
+{
+	bool was_present;
+
+	was_present = sc->child != NULL;
+
+	if (!was_present && is_present) {
+		taskqueue_enqueue_timeout(taskqueue_swi_giant,
+		  &sc->card_delayed_task, -(hz / 2));
+	} else if (was_present && !is_present) {
+		taskqueue_enqueue(taskqueue_swi_giant, &sc->card_task);
+	}
+}
+
+static void
+dwmmc_card_task(void *arg, int pending __unused)
+{
+	struct dwmmc_softc *sc = arg;
+
+	DWMMC_LOCK(sc);
+
+	if (READ4(sc, SDMMC_CDETECT) == 0) {
+		if (sc->child == NULL) {
+			if (bootverbose)
+				device_printf(sc->dev, "Card inserted\n");
+
+			sc->child = device_add_child(sc->dev, "mmc", -1);
+			DWMMC_UNLOCK(sc);
+			if (sc->child) {
+				device_set_ivars(sc->child, sc);
+				(void)device_probe_and_attach(sc->child);
+			}
+		} else
+			DWMMC_UNLOCK(sc);
+		
+	} else {
+		/* Card isn't present, detach if necessary */
+		if (sc->child != NULL) {
+			if (bootverbose)
+				device_printf(sc->dev, "Card removed\n");
+
+			DWMMC_UNLOCK(sc);
+			device_delete_child(sc->dev, sc->child);
+			sc->child = NULL;
+		} else
+			DWMMC_UNLOCK(sc);
+	}
+}
+
 static int
 parse_fdt(struct dwmmc_softc *sc)
 {
@@ -677,8 +731,17 @@ dwmmc_attach(device_t dev)
 	sc->host.caps |= MMC_CAP_HSPEED;
 	sc->host.caps |= MMC_CAP_SIGNALING_330;
 
-	sc->child = device_add_child(dev, "mmc", -1);
-	return (bus_generic_attach(dev));
+	TASK_INIT(&sc->card_task, 0, dwmmc_card_task, sc);
+	TIMEOUT_TASK_INIT(taskqueue_swi_giant, &sc->card_delayed_task, 0,
+		dwmmc_card_task, sc);
+
+	/* 
+	 * Schedule a card detection as we won't get an interrupt
+	 * if the card is inserted when we attach
+	 */
+	dwmmc_card_task(sc, 0);
+
+	return (0);
 }
 
 int
@@ -693,7 +756,9 @@ dwmmc_detach(device_t dev)
 	if (ret != 0)
 		return (ret);
 
-	DWMMC_LOCK_DESTROY(sc);
+	taskqueue_drain(taskqueue_swi_giant, &sc->card_task);
+	taskqueue_drain_timeout(taskqueue_swi_giant, &sc->card_delayed_task);
+
 	if (sc->intr_cookie != NULL) {
 		ret = bus_teardown_intr(dev, sc->res[1], sc->intr_cookie);
 		if (ret != 0)
@@ -706,6 +771,8 @@ dwmmc_detach(device_t dev)
 		if (ret != 0)
 			return (ret);
 	}
+
+	DWMMC_LOCK_DESTROY(sc);
 
 #ifdef EXT_RESOURCES
 	if (sc->hwreset != NULL && hwreset_deassert(sc->hwreset) != 0)

Modified: head/sys/dev/mmc/host/dwmmc_altera.c
==============================================================================
--- head/sys/dev/mmc/host/dwmmc_altera.c	Wed Dec 11 18:43:39 2019	(r355626)
+++ head/sys/dev/mmc/host/dwmmc_altera.c	Wed Dec 11 18:50:23 2019	(r355627)
@@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/module.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
 
 #include <machine/bus.h>
 

Modified: head/sys/dev/mmc/host/dwmmc_hisi.c
==============================================================================
--- head/sys/dev/mmc/host/dwmmc_hisi.c	Wed Dec 11 18:43:39 2019	(r355626)
+++ head/sys/dev/mmc/host/dwmmc_hisi.c	Wed Dec 11 18:50:23 2019	(r355627)
@@ -32,6 +32,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/module.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
 
 #include <machine/bus.h>
 

Modified: head/sys/dev/mmc/host/dwmmc_rockchip.c
==============================================================================
--- head/sys/dev/mmc/host/dwmmc_rockchip.c	Wed Dec 11 18:43:39 2019	(r355626)
+++ head/sys/dev/mmc/host/dwmmc_rockchip.c	Wed Dec 11 18:50:23 2019	(r355627)
@@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/module.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
 
 #include <machine/bus.h>
 

Modified: head/sys/dev/mmc/host/dwmmc_samsung.c
==============================================================================
--- head/sys/dev/mmc/host/dwmmc_samsung.c	Wed Dec 11 18:43:39 2019	(r355626)
+++ head/sys/dev/mmc/host/dwmmc_samsung.c	Wed Dec 11 18:50:23 2019	(r355627)
@@ -31,6 +31,8 @@ __FBSDID("$FreeBSD$");
 #include <sys/kernel.h>
 #include <sys/bus.h>
 #include <sys/module.h>
+#include <sys/queue.h>
+#include <sys/taskqueue.h>
 
 #include <machine/bus.h>
 

Modified: head/sys/dev/mmc/host/dwmmc_var.h
==============================================================================
--- head/sys/dev/mmc/host/dwmmc_var.h	Wed Dec 11 18:43:39 2019	(r355626)
+++ head/sys/dev/mmc/host/dwmmc_var.h	Wed Dec 11 18:50:23 2019	(r355627)
@@ -62,6 +62,8 @@ struct dwmmc_softc {
 	uint32_t		pwren_inverted;
 	u_int			desc_count;
 	device_t		child;
+	struct task		card_task;	/* Card presence check task */
+	struct timeout_task	card_delayed_task;/* Card insert delayed task */
 
 	int			(*update_ios)(struct dwmmc_softc *sc, struct mmc_ios *ios);
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201912111850.xBBIoNDT020038>