[PATCH v3] mmc: core: enhance card remove detection for gpio detect

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Current code detect card removal only by judging the result of
sending cmd13 to card, which is not safe for card with external
gpio detection. The communication status between host and card
may out of sync with the external gpio status if remove the card
slowly or hands shake during the process. The reason is the async
between card detect and pin contact in slot/card hardware.

The sequence is below when the issue occur (remove the card slowly):
1. gpio level changed and card detect interrupt triggered.
2. mmc_rescan is launched.
3. the card pin is still contacted with the slot because of slow
   removal. So _mmc_detect_card_removed and mmc_rescan think card is
   still present.
4. card pin is disconnected from the card slot pin contact.
So the card is really removed finally but the card removal event
has been missed by system.
The interval length between step 1 and step 4 depends on the
card removal speed. If it's longer than the detect work schedule
delay which is 200ms, this issue will likely happen.

For a card with external gpio detection, this patch add the
gpio detection into consideration when detect card removal.
If the gpio status and cmd13 result are out of sync then schedule
another detect work 200ms later.

This patch won't impact to cards not using gpio detection.

Signed-off-by: Kevin Liu <kliu5@xxxxxxxxxxx>
---
 drivers/mmc/core/core.c |   17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index b8c3d41..897ceb2 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -32,6 +32,7 @@
 #include <linux/mmc/host.h>
 #include <linux/mmc/mmc.h>
 #include <linux/mmc/sd.h>
+#include <linux/mmc/slot-gpio.h>
 
 #include "core.h"
 #include "bus.h"
@@ -2281,7 +2282,7 @@ static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
 
 int _mmc_detect_card_removed(struct mmc_host *host)
 {
-	int ret;
+	int ret, gpio_cd;
 
 	if ((host->caps & MMC_CAP_NONREMOVABLE) || !host->bus_ops->alive)
 		return 0;
@@ -2290,6 +2291,20 @@ int _mmc_detect_card_removed(struct mmc_host *host)
 		return 1;
 
 	ret = host->bus_ops->alive(host);
+	/*
+	 * If card use gpio detection then the gpio status and alive check
+	 * may out of sync because of the async between card detect and
+	 * pin contact in slot hardware. So schedule a detect work 200ms
+	 * later in this case.
+	 */
+	gpio_cd = mmc_gpio_get_cd(host);
+	if (!IS_ERR_VALUE(gpio_cd)) {
+		if (!ret ^ !!gpio_cd) {
+			mmc_detect_change(host, msecs_to_jiffies(200));
+			pr_warn("%s: card insert/remove too slowly\n",
+					mmc_hostname(host));
+		}
+	}
 	if (ret) {
 		mmc_card_set_removed(host->card);
 		pr_debug("%s: card remove detected\n", mmc_hostname(host));
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux