From d94e2bd60b27f2ff7d6e9ff7ee43848bb2090c06 Mon Sep 17 00:00:00 2001 From: dero Date: Mon, 19 Nov 2012 12:46:06 +0100 Subject: [PATCH 038/196] Lazy CRC quirk: Implemented retrying mechanisms for SD SSR and SCR, disabled missing_status and spurious CRC ACMD51 quirks by default (should be fixed by the retrying-mechanishm) --- drivers/mmc/core/sd.c | 115 +++++++++++++++++++++++++++++++++------ drivers/mmc/host/sdhci-bcm2708.c | 11 +++- 2 files changed, 108 insertions(+), 18 deletions(-) diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c index 9e645e1..1ee6cf3 100644 --- a/drivers/mmc/core/sd.c +++ b/drivers/mmc/core/sd.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include @@ -58,6 +60,15 @@ static const unsigned int tacc_mant[] = { __res & __mask; \ }) +// timeout for tries +static const unsigned long retry_timeout_ms= 10*1000; + +// try at least 10 times, even if timeout is reached +static const int retry_min_tries= 10; + +// delay between tries +static const unsigned long retry_delay_ms= 10; + /* * Given the decoded CSD structure, decode the raw CID to our CID structure. */ @@ -210,12 +221,62 @@ static int mmc_decode_scr(struct mmc_card *card) } /* - * Fetch and process SD Status register. + * Fetch and process SD Configuration Register. + */ +static int mmc_read_scr(struct mmc_card *card) +{ + unsigned long timeout_at; + int err, tries; + + timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms ); + tries= 0; + + while( tries < retry_min_tries || time_before( jiffies, timeout_at ) ) + { + unsigned long delay_at; + tries++; + + err = mmc_app_send_scr(card, card->raw_scr); + if( !err ) + break; // sucess!!! + + touch_nmi_watchdog(); // we are still alive! + + // delay + delay_at= jiffies + msecs_to_jiffies( retry_delay_ms ); + while( time_before( jiffies, delay_at ) ) + { + mdelay( 1 ); + touch_nmi_watchdog(); // we are still alive! + } + } + + if( err) + { + pr_err("%s: failed to read SD Configuration register (SCR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err ); + return err; + } + + if( tries > 1 ) + { + pr_info("%s: could read SD Configuration register (SCR) at the %dth attempt\n", mmc_hostname(card->host), tries ); + } + + err = mmc_decode_scr(card); + if (err) + return err; + + return err; +} + +/* + * Fetch and process SD Status Register. */ static int mmc_read_ssr(struct mmc_card *card) { + unsigned long timeout_at; unsigned int au, es, et, eo; - int err, i; + int err, i, tries; u32 *ssr; if (!(card->csd.cmdclass & CCC_APP_SPEC)) { @@ -227,15 +288,41 @@ static int mmc_read_ssr(struct mmc_card *card) ssr = kmalloc(64, GFP_KERNEL); if (!ssr) return -ENOMEM; - - err = mmc_app_sd_status(card, ssr); - if (err) { - pr_warning("%s: problem reading SD Status " - "register.\n", mmc_hostname(card->host)); - err = 0; + + timeout_at= jiffies + msecs_to_jiffies( retry_timeout_ms ); + tries= 0; + + while( tries < retry_min_tries || time_before( jiffies, timeout_at ) ) + { + unsigned long delay_at; + tries++; + + err= mmc_app_sd_status(card, ssr); + if( !err ) + break; // sucess!!! + + touch_nmi_watchdog(); // we are still alive! + + // delay + delay_at= jiffies + msecs_to_jiffies( retry_delay_ms ); + while( time_before( jiffies, delay_at ) ) + { + mdelay( 1 ); + touch_nmi_watchdog(); // we are still alive! + } + } + + if( err) + { + pr_err("%s: failed to read SD Status register (SSR) after %d tries during %lu ms, error %d\n", mmc_hostname(card->host), tries, retry_timeout_ms, err ); goto out; } + if( tries > 1 ) + { + pr_info("%s: could read SD Status register (SSR) at the %dth attempt\n", mmc_hostname(card->host), tries ); + } + for (i = 0; i < 16; i++) ssr[i] = be32_to_cpu(ssr[i]); @@ -808,15 +895,11 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card, if (!reinit) { /* - * Fetch SCR from card. + * Fetch and decode SD Configuration register. */ - err = mmc_app_send_scr(card, card->raw_scr); - if (err) - return err; - - err = mmc_decode_scr(card); - if (err) - return err; + err = mmc_read_scr(card); + if( err ) + return err; /* * Fetch and process SD Status register. diff --git a/drivers/mmc/host/sdhci-bcm2708.c b/drivers/mmc/host/sdhci-bcm2708.c index ffd7310..3556ed3 100644 --- a/drivers/mmc/host/sdhci-bcm2708.c +++ b/drivers/mmc/host/sdhci-bcm2708.c @@ -137,6 +137,7 @@ static bool allow_highspeed = 1; static int emmc_clock_freq = BCM2708_EMMC_CLOCK_FREQ; static bool sync_after_dma = 1; static bool missing_status = 1; +static bool spurious_crc_acmd51 = 0; bool enable_llm = 1; #if 0 @@ -1103,7 +1104,7 @@ static unsigned int sdhci_bcm2708_quirk_extra_ints(struct sdhci_host *host) return 1; } -static unsigned int sdhci_bcm2708_quirk_spurious_crc(struct sdhci_host *host) +static unsigned int sdhci_bcm2708_quirk_spurious_crc_acmd51(struct sdhci_host *host) { return 1; } @@ -1149,7 +1150,6 @@ static struct sdhci_ops sdhci_bcm2708_ops = { .pdma_reset = sdhci_bcm2708_platdma_reset, #endif .extra_ints = sdhci_bcm2708_quirk_extra_ints, - .spurious_crc_acmd51 = sdhci_bcm2708_quirk_spurious_crc, .voltage_broken = sdhci_bcm2708_quirk_voltage_broken, .uhs_broken = sdhci_bcm2708_uhs_broken, }; @@ -1194,6 +1194,11 @@ static int sdhci_bcm2708_probe(struct platform_device *pdev) sdhci_bcm2708_ops.missing_status = sdhci_bcm2708_missing_status; } + if( spurious_crc_acmd51 ) { + sdhci_bcm2708_ops.spurious_crc_acmd51 = sdhci_bcm2708_quirk_spurious_crc_acmd51; + } + + printk("sdhci: %s low-latency mode\n",enable_llm?"Enable":"Disable"); host->hw_name = "BCM2708_Arasan"; @@ -1389,6 +1394,7 @@ module_param(allow_highspeed, bool, 0444); module_param(emmc_clock_freq, int, 0444); module_param(sync_after_dma, bool, 0444); module_param(missing_status, bool, 0444); +module_param(spurious_crc_acmd51, bool, 0444); module_param(enable_llm, bool, 0444); module_param(cycle_delay, int, 0444); @@ -1401,6 +1407,7 @@ MODULE_PARM_DESC(allow_highspeed, "Allow high speed transfers modes"); MODULE_PARM_DESC(emmc_clock_freq, "Specify the speed of emmc clock"); MODULE_PARM_DESC(sync_after_dma, "Block in driver until dma complete"); MODULE_PARM_DESC(missing_status, "Use the missing status quirk"); +MODULE_PARM_DESC(spurious_crc_acmd51, "Use the spurious crc quirk for reading SCR (ACMD51)"); MODULE_PARM_DESC(enable_llm, "Enable low-latency mode"); -- 1.9.1