From: Chuanxiao Dong Date: Fri, 11 May 2012 09:43:52 +0000 (+0800) Subject: mmc: host: SD detection flow optimization X-Git-Tag: 2.1b_release~693 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1c525e8b86f40bf4dc42c0e8bca27a057ff4137e;p=kernel%2Fkernel-mfld-blackbay.git mmc: host: SD detection flow optimization BZ: 38199 With continously insert/remove a SD card on Tablet, Fabric error or kernel panic can happen, which would hang up the system. As original design, when there happens error during sending command to device, host controller needs to be reset to go back to a clean state. This patch will change this. If there error is NOMEDIA, means SD card is removed, host controller will not be reset until SD card is plugged again. This makes sense. This patch cannot workaround Fabric error, but seems can reduce the kernel panic Change-Id: I543b118305ee535fbdd9e03f15628b8622edcaa4 Signed-off-by: Chuanxiao Dong Reviewed-on: http://android.intel.com:8080/50108 Tested-by: Sun, Jianhua Reviewed-by: Tang, Richard Reviewed-by: buildbot Tested-by: buildbot --- diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c index 6cd3cdc..20c5fc5 100644 --- a/drivers/mmc/host/sdhci-pci.c +++ b/drivers/mmc/host/sdhci-pci.c @@ -1259,11 +1259,27 @@ static int sdhci_pci_power_up_host(struct sdhci_host *host) #define sdhci_pci_power_up_host NULL #endif +static int sdhci_pci_get_cd(struct sdhci_host *host) +{ + bool present; + + /* If nonremovable or polling, assume that the card is always present */ + if ((host->mmc->caps & MMC_CAP_NONREMOVABLE) || + (host->quirks & SDHCI_QUIRK_BROKEN_CARD_DETECTION)) + present = true; + else + present = sdhci_readl(host, SDHCI_PRESENT_STATE) & + SDHCI_CARD_PRESENT; + + return present; +} + static struct sdhci_ops sdhci_pci_ops = { .enable_dma = sdhci_pci_enable_dma, .platform_8bit_width = sdhci_pci_8bit_width, .hw_reset = sdhci_pci_hw_reset, .power_up_host = sdhci_pci_power_up_host, + .get_cd = sdhci_pci_get_cd, }; /*****************************************************************************\ diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index b1b1610..4aa2317 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2123,6 +2123,20 @@ static void sdhci_enable_preset_value(struct mmc_host *mmc, bool enable) sdhci_runtime_pm_put(host); } +static int sdhci_get_cd(struct mmc_host *mmc) +{ + struct sdhci_host *host = mmc_priv(mmc); + int present = -EOPNOTSUPP; + + if (host->ops->get_cd) { + sdhci_runtime_pm_get(host); + present = host->ops->get_cd(host); + sdhci_runtime_pm_put(host); + } + + return present; +} + static const struct mmc_host_ops sdhci_ops = { .request = sdhci_request, .set_ios = sdhci_set_ios, @@ -2132,6 +2146,7 @@ static const struct mmc_host_ops sdhci_ops = { .start_signal_voltage_switch = sdhci_start_signal_voltage_switch, .execute_tuning = sdhci_execute_tuning, .enable_preset_value = sdhci_enable_preset_value, + .get_cd = sdhci_get_cd, }; /*****************************************************************************\ @@ -2147,6 +2162,8 @@ static void sdhci_tasklet_card(unsigned long param) host = (struct sdhci_host*)param; + cancel_delayed_work(&host->mmc->detect); + spin_lock_irqsave(&host->lock, flags); /* Check host->mrq first in case we are runtime suspended */ @@ -2166,7 +2183,7 @@ static void sdhci_tasklet_card(unsigned long param) spin_unlock_irqrestore(&host->lock, flags); - mmc_detect_change(host->mmc, msecs_to_jiffies(200)); + mmc_detect_change(host->mmc, msecs_to_jiffies(500)); } static void sdhci_tasklet_finish(unsigned long param) @@ -2197,7 +2214,7 @@ static void sdhci_tasklet_finish(unsigned long param) * upon error conditions. */ if (!(host->flags & SDHCI_DEVICE_DEAD) && - ((mrq->cmd && mrq->cmd->error) || + ((mrq->cmd && mrq->cmd->error && mrq->cmd->error != -ENOMEDIUM) || (mrq->data && (mrq->data->error || (mrq->data->stop && mrq->data->stop->error))) || (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) { diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 6a5914e..fcf0b45 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -275,6 +275,7 @@ struct sdhci_ops { int (*set_uhs_signaling)(struct sdhci_host *host, unsigned int uhs); void (*hw_reset)(struct sdhci_host *host); int (*power_up_host)(struct sdhci_host *host); + int (*get_cd)(struct sdhci_host *host); }; #ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS