diff options
author | Adrian Hunter <adrian.hunter@intel.com> | 2016-10-05 12:11:21 +0300 |
---|---|---|
committer | Ulf Hansson <ulf.hansson@linaro.org> | 2016-10-10 15:20:34 +0300 |
commit | fc605f1d8060133596bb6083fc4b7b306d1d5931 (patch) | |
tree | 3036ddd4e1667fc847ea8bea31cd22b712a79d2d /drivers/mmc/host/sdhci.c | |
parent | 3f2d26643595973e835e8356ea90c7c15cb1b0f1 (diff) | |
download | linux-fc605f1d8060133596bb6083fc4b7b306d1d5931.tar.xz |
mmc: sdhci: Fix SDHCI_QUIRK2_STOP_WITH_TC
Multi-block data transfers can specify the number of blocks either using a
Set Block Count command (CMD23) or by sending a STOP command (CMD12) after
the required number of blocks has transferred. CMD23 is preferred, but some
cards don't support it. CMD12 with R1b response is used for writes, and
R1 response for reads.
Some SDHCI host controllers give a Transfer Complete (TC) interrupt for the
STOP command (CMD12) whether or not a R1b response has been specified. The
quirk SDHCI_QUIRK2_STOP_WITH_TC identifies those host controllers, but the
implementation only considers the case where the TC interrupt arrives at
the same time as the Command Complete (CC) interrupt. However,
occasionally TC arrives before CC. That is harmless, but does generate an
error message "Got data interrupt 0x00000002 even though no data operation
was in progress".
A simpler approach is to force R1b response onto all STOP commands, because
SDHCI will handle TC before CC in the general case, so do that.
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Diffstat (limited to 'drivers/mmc/host/sdhci.c')
-rw-r--r-- | drivers/mmc/host/sdhci.c | 14 |
1 files changed, 6 insertions, 8 deletions
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 48055666c655..3711813f5654 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -1077,6 +1077,10 @@ void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd) /* Initially, a command has no error */ cmd->error = 0; + if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) && + cmd->opcode == MMC_STOP_TRANSMISSION) + cmd->flags |= MMC_RSP_BUSY; + /* Wait max 10 ms */ timeout = 10; @@ -2409,7 +2413,7 @@ static void sdhci_timeout_data_timer(unsigned long data) * * \*****************************************************************************/ -static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) +static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask) { if (!host->cmd) { /* @@ -2453,11 +2457,6 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask) return; } - if ((host->quirks2 & SDHCI_QUIRK2_STOP_WITH_TC) && - !(host->cmd->flags & MMC_RSP_BUSY) && !host->data && - host->cmd->opcode == MMC_STOP_TRANSMISSION) - *mask &= ~SDHCI_INT_DATA_END; - if (intmask & SDHCI_INT_RESPONSE) sdhci_finish_command(host); } @@ -2680,8 +2679,7 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) } if (intmask & SDHCI_INT_CMD_MASK) - sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK, - &intmask); + sdhci_cmd_irq(host, intmask & SDHCI_INT_CMD_MASK); if (intmask & SDHCI_INT_DATA_MASK) sdhci_data_irq(host, intmask & SDHCI_INT_DATA_MASK); |