Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=e538fbe83e374a3521128c1f4642aca037661c9d
Commit:     e538fbe83e374a3521128c1f4642aca037661c9d
Parent:     03f8590d90844f04d20488a80e75eaf4c4e0b35c
Author:     Pierre Ossman <[EMAIL PROTECTED]>
AuthorDate: Sun Aug 12 16:46:32 2007 +0200
Committer:  Pierre Ossman <[EMAIL PROTECTED]>
CommitDate: Thu Aug 23 06:30:53 2007 +0200

    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 <[EMAIL PROTECTED]>
---
 drivers/mmc/host/sdhci.c |   28 +++++++++++++++++++++-------
 drivers/mmc/host/sdhci.h |    1 +
 2 files changed, 22 insertions(+), 7 deletions(-)

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 @@ 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);
+                       }
+               }
        }
 }
 
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index d157776..e28987d 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -182,6 +182,7 @@ struct sdhci_host {
        struct mmc_request      *mrq;           /* Current request */
        struct mmc_command      *cmd;           /* Current command */
        struct mmc_data         *data;          /* Current data request */
+       int                     data_early:1;   /* Data finished before cmd */
 
        struct scatterlist      *cur_sg;        /* We're working on this */
        int                     num_sg;         /* Entries left */
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to