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 <drzeus@drzeus.cx>
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 2b327b4..f8fc0a9 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -385,6 +385,9 @@
 	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 @@
 {
 	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 @@
 
 	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 @@
 			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);
+			}
+		}
 	}
 }