]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/mmc/host/sdhci.c
mmc: check error bits before command completion
[linux-2.6-omap-h63xx.git] / drivers / mmc / host / sdhci.c
index ff5bf73cdd25656bcc41df6b1dc9e7e03e4d42f0..56de4c48ec80337e523be74a5609367a39e751bc 100644 (file)
@@ -70,6 +70,14 @@ static const struct pci_device_id pci_ids[] __devinitdata = {
                .driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE,
        },
 
+       {
+               .vendor         = PCI_VENDOR_ID_ENE,
+               .device         = PCI_DEVICE_ID_ENE_CB712_SD_2,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .driver_data    = SDHCI_QUIRK_SINGLE_POWER_WRITE,
+       },
+
        {       /* Generic SD host controller */
                PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
        },
@@ -914,20 +922,17 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
                return;
        }
 
-       if (intmask & SDHCI_INT_RESPONSE)
-               sdhci_finish_command(host);
-       else {
-               if (intmask & SDHCI_INT_TIMEOUT)
-                       host->cmd->error = MMC_ERR_TIMEOUT;
-               else if (intmask & SDHCI_INT_CRC)
-                       host->cmd->error = MMC_ERR_BADCRC;
-               else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
-                       host->cmd->error = MMC_ERR_FAILED;
-               else
-                       host->cmd->error = MMC_ERR_INVALID;
+       if (intmask & SDHCI_INT_TIMEOUT)
+               host->cmd->error = MMC_ERR_TIMEOUT;
+       else if (intmask & SDHCI_INT_CRC)
+               host->cmd->error = MMC_ERR_BADCRC;
+       else if (intmask & (SDHCI_INT_END_BIT | SDHCI_INT_INDEX))
+               host->cmd->error = MMC_ERR_FAILED;
 
+       if (host->cmd->error != MMC_ERR_NONE)
                tasklet_schedule(&host->finish_tasklet);
-       }
+       else if (intmask & SDHCI_INT_RESPONSE)
+               sdhci_finish_command(host);
 }
 
 static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
@@ -963,6 +968,15 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
                if (intmask & (SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL))
                        sdhci_transfer_pio(host);
 
+               /*
+                * We currently don't do anything fancy with DMA
+                * boundaries, but as we can't disable the feature
+                * we need to at least restart the transfer.
+                */
+               if (intmask & SDHCI_INT_DMA_END)
+                       writel(readl(host->ioaddr + SDHCI_DMA_ADDRESS),
+                               host->ioaddr + SDHCI_DMA_ADDRESS);
+
                if (intmask & SDHCI_INT_DATA_END)
                        sdhci_finish_data(host);
        }
@@ -1007,13 +1021,15 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id)
 
        intmask &= ~(SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK);
 
+       intmask &= ~SDHCI_INT_ERROR;
+
        if (intmask & SDHCI_INT_BUS_POWER) {
                printk(KERN_ERR "%s: Card is consuming too much power!\n",
                        mmc_hostname(host->mmc));
                writel(SDHCI_INT_BUS_POWER, host->ioaddr + SDHCI_INT_STATUS);
        }
 
-       intmask &= SDHCI_INT_BUS_POWER;
+       intmask &= ~SDHCI_INT_BUS_POWER;
 
        if (intmask) {
                printk(KERN_ERR "%s: Unexpected interrupt 0x%08x.\n",