Skip to content

Commit

Permalink
Merge pull request #159 from derolf/rpi-3.2.27
Browse files Browse the repository at this point in the history
Lazy CRC quirk: Implemented retrying mechanisms for SD SSR and SCR, disa...
  • Loading branch information
popcornmix committed Nov 26, 2012
2 parents 00c4bfd + 22e8df6 commit ef20553
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 19 deletions.
115 changes: 99 additions & 16 deletions drivers/mmc/core/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/jiffies.h>
#include <linux/nmi.h>

#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
Expand Down Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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)) {
Expand All @@ -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]);

Expand Down Expand Up @@ -803,15 +890,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.
Expand Down
13 changes: 10 additions & 3 deletions drivers/mmc/host/sdhci-bcm2708.c
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ static inline unsigned long int since_ns(hptime_t t)
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 missing_status = 0;
static bool spurious_crc_acmd51 = 0;
bool enable_llm = 1;

#if 0
Expand Down Expand Up @@ -1220,7 +1221,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;
}
Expand Down Expand Up @@ -1270,7 +1271,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,
};
Expand Down Expand Up @@ -1315,6 +1315,11 @@ static int __devinit 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";
Expand Down Expand Up @@ -1518,6 +1523,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);

Expand All @@ -1530,6 +1536,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");


0 comments on commit ef20553

Please sign in to comment.