Skip to content

Lazy CRC quirk: Implemented retrying mechanisms for SD SSR and SCR, disa... #159

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 26, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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");