[MMC] sdhci: more DMA capabilities tests
authorPierre Ossman <drzeus@drzeus.cx>
Fri, 30 Jun 2006 09:22:31 +0000 (02:22 -0700)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sun, 2 Jul 2006 15:54:56 +0000 (16:54 +0100)
Properly test for controller interface to see if it's DMA capable.  As many
controllers are misconfigured in this regard, also add debug parameters to
force DMA support either way.

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
drivers/mmc/sdhci.c
drivers/mmc/sdhci.h

index 06dec74..315ab49 100644 (file)
@@ -28,6 +28,9 @@
 #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 const struct pci_device_id pci_ids[] __devinitdata = {
        /* handle any SD host controller */
        {PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)},
@@ -1105,6 +1108,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;
@@ -1146,7 +1159,16 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot)
 
        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) {
@@ -1429,7 +1451,13 @@ 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_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)");
index 758cf1c..8111fa3 100644 (file)
  * PCI registers
  */
 
+#define PCI_SDHCI_IFPIO                        0x00
+#define PCI_SDHCI_IFDMA                        0x01
+#define PCI_SDHCI_IFVENDOR             0x02
+
 #define PCI_SLOT_INFO                  0x40    /* 8 bits */
 #define  PCI_SLOT_INFO_SLOTS(x)                ((x >> 4) & 7)
 #define  PCI_SLOT_INFO_FIRST_BAR_MASK  0x07