diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-11-26 08:22:50 +0100 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-11-26 08:22:50 +0100 |
commit | 7fbb8759eff9a348efa5f352ffaa51c364837c4b (patch) | |
tree | d40cd3f47b9f667ba94d9613270132080dcb6a1a /drivers/mmc/host/sdhci.c | |
parent | 6003ab0bad4cc56f3c4fadf62a0d23a967b9c53b (diff) | |
parent | 13d428afc007fcfcd6deeb215618f54cf9c0cae6 (diff) |
Merge commit 'v2.6.28-rc6' into core/debug
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 48 |
1 files changed, 38 insertions, 10 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index e3a8133560a..4d010a984be 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"); @@ -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) @@ -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", @@ -1604,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; @@ -1705,7 +1733,7 @@ int sdhci_add_host(struct sdhci_host *host) mmc_add_host(mmc); printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s%s\n", - mmc_hostname(mmc), host->hw_name, mmc_dev(mmc)->bus_id, + mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)), (host->flags & SDHCI_USE_ADMA)?"A":"", (host->flags & SDHCI_USE_DMA)?"DMA":"PIO"); |