}
 }
 
+static void sdhci_mod_timer(struct sdhci_host *host, struct mmc_request *mrq,
+                           unsigned long timeout)
+{
+       if (sdhci_data_line_cmd(mrq->cmd))
+               mod_timer(&host->data_timer, timeout);
+       else
+               mod_timer(&host->timer, timeout);
+}
+
+static void sdhci_del_timer(struct sdhci_host *host, struct mmc_request *mrq)
+{
+       if (sdhci_data_line_cmd(mrq->cmd))
+               del_timer(&host->data_timer);
+       else
+               del_timer(&host->timer);
+}
+
 void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 {
        int flags;
                timeout += DIV_ROUND_UP(cmd->busy_timeout, 1000) * HZ + HZ;
        else
                timeout += 10 * HZ;
-       mod_timer(&host->timer, timeout);
+       sdhci_mod_timer(host, cmd->mrq, timeout);
 
        host->cmd = cmd;
        if (sdhci_data_line_cmd(cmd)) {
                return;
        }
 
-       del_timer(&host->timer);
-
        mrq = host->mrq;
 
+       sdhci_del_timer(host, mrq);
+
        /*
         * Always unmap the data buffers if they were mapped by
         * sdhci_prepare_data() whenever we finish with a request.
 
        spin_lock_irqsave(&host->lock, flags);
 
-       if (host->mrq) {
+       if (host->cmd && !sdhci_data_line_cmd(host->cmd)) {
+               pr_err("%s: Timeout waiting for hardware cmd interrupt.\n",
+                      mmc_hostname(host->mmc));
+               sdhci_dumpregs(host);
+
+               host->cmd->error = -ETIMEDOUT;
+               sdhci_finish_mrq(host, host->cmd->mrq);
+       }
+
+       mmiowb();
+       spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void sdhci_timeout_data_timer(unsigned long data)
+{
+       struct sdhci_host *host;
+       unsigned long flags;
+
+       host = (struct sdhci_host *)data;
+
+       spin_lock_irqsave(&host->lock, flags);
+
+       if (host->data || host->data_cmd ||
+           (host->cmd && sdhci_data_line_cmd(host->cmd))) {
                pr_err("%s: Timeout waiting for hardware interrupt.\n",
                       mmc_hostname(host->mmc));
                sdhci_dumpregs(host);
                if (host->data) {
                        host->data->error = -ETIMEDOUT;
                        sdhci_finish_data(host);
+               } else if (host->data_cmd) {
+                       host->data_cmd->error = -ETIMEDOUT;
+                       sdhci_finish_mrq(host, host->data_cmd->mrq);
                } else {
-                       if (host->cmd)
-                               host->cmd->error = -ETIMEDOUT;
-                       else
-                               host->mrq->cmd->error = -ETIMEDOUT;
-
-                       sdhci_finish_mrq(host, host->mrq);
+                       host->cmd->error = -ETIMEDOUT;
+                       sdhci_finish_mrq(host, host->cmd->mrq);
                }
        }
 
                sdhci_tasklet_finish, (unsigned long)host);
 
        setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
+       setup_timer(&host->data_timer, sdhci_timeout_data_timer,
+                   (unsigned long)host);
 
        init_waitqueue_head(&host->buf_ready_int);
 
        free_irq(host->irq, host);
 
        del_timer_sync(&host->timer);
+       del_timer_sync(&host->data_timer);
 
        tasklet_kill(&host->finish_tasklet);