From e809517f6fa5803a5a1cd56026f0e2190fc13d5c Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Fri, 25 Jul 2008 01:09:08 +0200 Subject: sdhci: let the controller wait for busy state to end The sdhci controllers can interrupt us when the busy state from the card has ended, saving CPU cycles and power. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index e3a8133560a..ef461274397 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1266,9 +1266,31 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) SDHCI_INT_INDEX)) host->cmd->error = -EILSEQ; - if (host->cmd->error) + if (host->cmd->error) { tasklet_schedule(&host->finish_tasklet); - else if (intmask & SDHCI_INT_RESPONSE) + return; + } + + /* + * The host can send and interrupt when the busy state has + * ended, allowing us to wait without wasting CPU cycles. + * Unfortunately this is overloaded on the "data complete" + * interrupt, so we need to take some care when handling + * it. + * + * Note: The 1.0 specification is a bit ambiguous about this + * feature so there might be some problems with older + * controllers. + */ + if (host->cmd->flags & MMC_RSP_BUSY) { + if (host->cmd->data) + DBG("Cannot wait for busy signal when also " + "doing a data transfer"); + else + return; + } + + if (intmask & SDHCI_INT_RESPONSE) sdhci_finish_command(host); } @@ -1278,11 +1300,16 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) if (!host->data) { /* - * A data end interrupt is sent together with the response - * for the stop command. + * The "data complete" interrupt is also used to + * indicate that a busy state has ended. See comment + * above in sdhci_cmd_irq(). */ - if (intmask & SDHCI_INT_DATA_END) - return; + if (host->cmd && (host->cmd->flags & MMC_RSP_BUSY)) { + if (intmask & SDHCI_INT_DATA_END) { + sdhci_finish_command(host); + return; + } + } printk(KERN_ERR "%s: Got data interrupt 0x%08x even " "though no data operation was in progress.\n", -- cgit v1.2.3 From 04cf585d2902404ed06861c6dc27897100340dba Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Mon, 18 Aug 2008 22:18:14 +0200 Subject: sdhci: reduce card detection delay The card detection delay was added early when the behaviour of the card interrupt was still very much unknown (i.e. before there was a public specification). As it is now known that it is a debounced signal, reduce the delay to something more sensible. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ef461274397..fd2dc821e40 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1154,7 +1154,7 @@ static void sdhci_tasklet_card(unsigned long param) spin_unlock_irqrestore(&host->lock, flags); - mmc_detect_change(host->mmc, msecs_to_jiffies(500)); + mmc_detect_change(host->mmc, msecs_to_jiffies(200)); } static void sdhci_tasklet_finish(unsigned long param) -- cgit v1.2.3 From a4b76193774b463b922cab2f92450efb20d29ef0 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sat, 16 Aug 2008 20:43:04 +0200 Subject: sdhci: force high speed capability on some controllers Some high speed capable controllers forget to set the high speed capability bit. Make sure we enable the functionality anyway. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index fd2dc821e40..3c808d22f9d 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1631,7 +1631,8 @@ int sdhci_add_host(struct sdhci_host *host) mmc->f_max = host->max_clk; mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; - if (caps & SDHCI_CAN_DO_HISPD) + if ((caps & SDHCI_CAN_DO_HISPD) || + (host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED)) mmc->caps |= MMC_CAP_SD_HIGHSPEED; mmc->ocr_avail = 0; -- cgit v1.2.3 From 7244b85bd17313d7d300ee93ec7bfbca1f4ccf3d Mon Sep 17 00:00:00 2001 From: Steven Noonan Date: Wed, 1 Oct 2008 01:50:25 -0700 Subject: sdhci: 'scratch' may be used uninitialized The variable 'scratch' is always initialized before it's used. The conditional which is responsible for initialization of 'scratch' will always evaluate 'true' when the first loop iteration occurs, and thus, it's properly initialized. GCC doesn't see this, of course, so using the uninitialized_var() macro seems to work for silencing this case. Signed-off-by: Steven Noonan Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 3c808d22f9d..30f64b1f235 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -177,7 +177,7 @@ static void sdhci_read_block_pio(struct sdhci_host *host) { unsigned long flags; size_t blksize, len, chunk; - u32 scratch; + u32 uninitialized_var(scratch); u8 *buf; DBG("PIO reading\n"); -- cgit v1.2.3