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 <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..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 majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html