|
@@ -385,6 +385,9 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
|
|
|
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 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
|
|
|
{
|
|
|
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 @@ static void sdhci_finish_command(struct sdhci_host *host)
|
|
|
|
|
|
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 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
|
|
|
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);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|