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. then card is really removed but the gpio level won't change
and detect work won't be scheduled and the card removal event
will be missed by system.

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 <kl...@marvell.com>
---
 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..4f438f5 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 (gpio_cd >= 0) {
+               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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to