From 2b061973404802fb87db93175b856ee0dfbe38e4 Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 12 Aug 2007 13:13:24 +0200 Subject: sdhci: be more cautious about block count register The block count register shouldn't be trusted for single block transfers, so avoid using it completely when calculating transferred bytes. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index f2bc87ac24f..7181e867863 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -477,8 +477,8 @@ static void sdhci_finish_data(struct sdhci_host *host) /* * Controller doesn't count down when in single block mode. */ - if ((data->blocks == 1) && (data->error == MMC_ERR_NONE)) - blocks = 0; + if (data->blocks == 1) + blocks = (data->error == MMC_ERR_NONE) ? 0 : 1; else blocks = readw(host->ioaddr + SDHCI_BLOCK_COUNT); data->bytes_xfered = data->blksz * (data->blocks - blocks); -- cgit v1.2.3 From 03f8590d90844f04d20488a80e75eaf4c4e0b35c Mon Sep 17 00:00:00 2001 From: David Vrabel Date: Fri, 10 Aug 2007 13:25:03 +0100 Subject: mmc: ignore bad max block size in sdhci Some SDHC cards report an invalid maximum block size, in these cases assume they support block sizes up to 512 bytes instead of returning an error. Signed-off-by: David Vrabel Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 7181e867863..2b327b40fa8 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1347,12 +1347,11 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) */ mmc->max_blk_size = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT; if (mmc->max_blk_size >= 3) { - printk(KERN_ERR "%s: Invalid maximum block size.\n", + printk(KERN_WARNING "%s: Invalid maximum block size, assuming 512\n", host->slot_descr); - ret = -ENODEV; - goto unmap; - } - mmc->max_blk_size = 512 << mmc->max_blk_size; + mmc->max_blk_size = 512; + } else + mmc->max_blk_size = 512 << mmc->max_blk_size; /* * Maximum block count. -- cgit v1.2.3 From e538fbe83e374a3521128c1f4642aca037661c9d Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 12 Aug 2007 16:46:32 +0200 Subject: sdhci: handle data interrupts during command It is fully legal for a controller to start issuing data related interrupts before it has signalled that the command has completed. Make sure the driver actually can handle this. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'drivers/mmc/host/sdhci.c') diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 2b327b40fa8..f8fc0a98b8c 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -385,6 +385,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) BUG_ON(data->blksz > host->mmc->max_blk_size); BUG_ON(data->blocks > 65535); + host->data = data; + host->data_early = 0; + /* timeout in us */ target_timeout = data->timeout_ns / 1000 + data->timeout_clks / host->clock; @@ -443,11 +446,11 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, { u16 mode; - WARN_ON(host->data); - if (data == NULL) return; + WARN_ON(!host->data); + mode = SDHCI_TRNS_BLK_CNT_EN; if (data->blocks > 1) mode |= SDHCI_TRNS_MULTI; @@ -600,9 +603,10 @@ static void sdhci_finish_command(struct sdhci_host *host) host->cmd->error = MMC_ERR_NONE; - if (host->cmd->data) - host->data = host->cmd->data; - else + if (host->data && host->data_early) + sdhci_finish_data(host); + + if (!host->cmd->data) tasklet_schedule(&host->finish_tasklet); host->cmd = NULL; @@ -991,8 +995,18 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS), host->ioaddr + SDHCI_DMA_ADDRESS); - if (intmask & SDHCI_INT_DATA_END) - sdhci_finish_data(host); + if (intmask & SDHCI_INT_DATA_END) { + if (host->cmd) { + /* + * Data managed to finish before the + * command completed. Make sure we do + * things in the proper order. + */ + host->data_early = 1; + } else { + sdhci_finish_data(host); + } + } } } -- cgit v1.2.3 From b67ac3f339c76dfea3cc75fc0285b6d13edc35fa Mon Sep 17 00:00:00 2001 From: Pierre Ossman Date: Sun, 12 Aug 2007 17:29:47 +0200 Subject: sdhci: tell which spurious interrupt we got When we get unexpected interrupts, also print which interrupt it was. Signed-off-by: Pierre Ossman --- drivers/mmc/host/sdhci.c | 12 ++++++------ 1 file changed, 6 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 f8fc0a98b8c..20a7d89e01b 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -933,9 +933,9 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) BUG_ON(intmask == 0); if (!host->cmd) { - printk(KERN_ERR "%s: Got command interrupt even though no " - "command operation was in progress.\n", - mmc_hostname(host->mmc)); + printk(KERN_ERR "%s: Got command interrupt 0x%08x even " + "though no command operation was in progress.\n", + mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); return; } @@ -965,9 +965,9 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) if (intmask & SDHCI_INT_DATA_END) return; - printk(KERN_ERR "%s: Got data interrupt even though no " - "data operation was in progress.\n", - mmc_hostname(host->mmc)); + printk(KERN_ERR "%s: Got data interrupt 0x%08x even " + "though no data operation was in progress.\n", + mmc_hostname(host->mmc), (unsigned)intmask); sdhci_dumpregs(host); return; -- cgit v1.2.3