sdhci: let the controller wait for busy state to end
authorPierre Ossman <drzeus@drzeus.cx>
Thu, 24 Jul 2008 23:09:08 +0000 (01:09 +0200)
committerPierre Ossman <drzeus@drzeus.cx>
Sun, 12 Oct 2008 09:04:27 +0000 (11:04 +0200)
The sdhci controllers can interrupt us when the busy state from the
card has ended, saving CPU cycles and power.

Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
drivers/mmc/host/sdhci.c

index e3a8133560a2b41a19f15dd193a83c80d5727e4f..ef461274397b52fb42da032a33db02f84e16f258 100644 (file)
@@ -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",