]> err.no Git - linux-2.6/blobdiff - drivers/mmc/sdhci.c
[MMC] sdhci: version bump sdhci
[linux-2.6] / drivers / mmc / sdhci.c
index 95fe0fdac4849a43f3f6d5345e92a7f61731fae8..e192f3c9a43789f0a82ce348f945e513bc2df3a2 100644 (file)
 #include "sdhci.h"
 
 #define DRIVER_NAME "sdhci"
-#define DRIVER_VERSION "0.11"
+#define DRIVER_VERSION "0.12"
 
 #define BUGMAIL "<sdhci-devel@list.drzeus.cx>"
 
 #define DBG(f, x...) \
        pr_debug(DRIVER_NAME " [%s()]: " f, __func__,## x)
 
+static unsigned int debug_nodma = 0;
+static unsigned int debug_forcedma = 0;
+static unsigned int debug_quirks = 0;
+
 static const struct pci_device_id pci_ids[] __devinitdata = {
        /* handle any SD host controller */
        {PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)},
@@ -328,6 +332,8 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 
        /* Sanity checks */
        BUG_ON(data->blksz * data->blocks > 524288);
+       BUG_ON(data->blksz > host->max_block);
+       BUG_ON(data->blocks > 65535);
 
        /* timeout in us */
        target_timeout = data->timeout_ns / 1000 +
@@ -463,6 +469,7 @@ static void sdhci_finish_data(struct sdhci_host *host)
 static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 {
        int flags;
+       u32 mask;
        unsigned long timeout;
 
        WARN_ON(host->cmd);
@@ -471,11 +478,20 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 
        /* Wait max 10 ms */
        timeout = 10;
-       while (readl(host->ioaddr + SDHCI_PRESENT_STATE) &
-               (SDHCI_CMD_INHIBIT | SDHCI_DATA_INHIBIT)) {
+
+       mask = SDHCI_CMD_INHIBIT;
+       if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
+               mask |= SDHCI_DATA_INHIBIT;
+
+       /* We shouldn't wait for data inihibit for stop commands, even
+          though they might use busy signaling */
+       if (host->mrq->data && (cmd == host->mrq->data->stop))
+               mask &= ~SDHCI_DATA_INHIBIT;
+
+       while (readl(host->ioaddr + SDHCI_PRESENT_STATE) & mask) {
                if (timeout == 0) {
                        printk(KERN_ERR "%s: Controller never released "
-                               "inhibit bits. Please report this to "
+                               "inhibit bit(s). Please report this to "
                                BUGMAIL ".\n", mmc_hostname(host->mmc));
                        sdhci_dumpregs(host);
                        cmd->error = MMC_ERR_FAILED;
@@ -1061,6 +1077,7 @@ static int sdhci_resume (struct pci_dev *pdev)
 static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 {
        int ret;
+       unsigned int version;
        struct sdhci_chip *chip;
        struct mmc_host *mmc;
        struct sdhci_host *host;
@@ -1092,6 +1109,16 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
                return -ENODEV;
        }
 
+       if ((pdev->class & 0x0000FF) == PCI_SDHCI_IFVENDOR) {
+               printk(KERN_ERR DRIVER_NAME ": Vendor specific interface. Aborting.\n");
+               return -ENODEV;
+       }
+
+       if ((pdev->class & 0x0000FF) > PCI_SDHCI_IFVENDOR) {
+               printk(KERN_ERR DRIVER_NAME ": Unknown interface. Aborting.\n");
+               return -ENODEV;
+       }
+
        mmc = mmc_alloc_host(sizeof(struct sdhci_host), &pdev->dev);
        if (!mmc)
                return -ENOMEM;
@@ -1119,9 +1146,30 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
                goto release;
        }
 
+       sdhci_reset(host, SDHCI_RESET_ALL);
+
+       version = readw(host->ioaddr + SDHCI_HOST_VERSION);
+       version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
+       if (version != 0) {
+               printk(KERN_ERR "%s: Unknown controller version (%d). "
+                       "Cowardly refusing to continue.\n", host->slot_descr,
+                       version);
+               ret = -ENODEV;
+               goto unmap;
+       }
+
        caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
 
-       if ((caps & SDHCI_CAN_DO_DMA) && ((pdev->class & 0x0000FF) == 0x01))
+       if (debug_nodma)
+               DBG("DMA forced off\n");
+       else if (debug_forcedma) {
+               DBG("DMA forced on\n");
+               host->flags |= SDHCI_USE_DMA;
+       } else if ((pdev->class & 0x0000FF) != PCI_SDHCI_IFDMA)
+               DBG("Controller doesn't have DMA interface\n");
+       else if (!(caps & SDHCI_CAN_DO_DMA))
+               DBG("Controller doesn't have DMA capability\n");
+       else
                host->flags |= SDHCI_USE_DMA;
 
        if (host->flags & SDHCI_USE_DMA) {
@@ -1158,6 +1206,15 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
        if (caps & SDHCI_TIMEOUT_CLK_UNIT)
                host->timeout_clk *= 1000;
 
+       host->max_block = (caps & SDHCI_MAX_BLOCK_MASK) >> SDHCI_MAX_BLOCK_SHIFT;
+       if (host->max_block >= 3) {
+               printk(KERN_ERR "%s: Invalid maximum block size.\n",
+                       host->slot_descr);
+               ret = -ENODEV;
+               goto unmap;
+       }
+       host->max_block = 512 << host->max_block;
+
        /*
         * Set host parameters.
         */
@@ -1317,6 +1374,10 @@ static int __devinit sdhci_probe(struct pci_dev *pdev,
        }
 
        chip->pdev = pdev;
+       chip->quirks = ent->driver_data;
+
+       if (debug_quirks)
+               chip->quirks = debug_quirks;
 
        chip->num_slots = slots;
        pci_set_drvdata(pdev, chip);
@@ -1395,7 +1456,15 @@ static void __exit sdhci_drv_exit(void)
 module_init(sdhci_drv_init);
 module_exit(sdhci_drv_exit);
 
+module_param(debug_nodma, uint, 0444);
+module_param(debug_forcedma, uint, 0444);
+module_param(debug_quirks, uint, 0444);
+
 MODULE_AUTHOR("Pierre Ossman <drzeus@drzeus.cx>");
 MODULE_DESCRIPTION("Secure Digital Host Controller Interface driver");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
+
+MODULE_PARM_DESC(debug_nodma, "Forcefully disable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_forcedma, "Forcefully enable DMA transfers. (default 0)");
+MODULE_PARM_DESC(debug_quirks, "Force certain quirks.");