| From 5c41ea6d52003b5bc77c2a82fd5ca7d480237d89 Mon Sep 17 00:00:00 2001 |
| From: Faiz Abbas <faiz_abbas@ti.com> |
| Date: Thu, 11 Apr 2019 14:29:37 +0530 |
| Subject: mmc: sdhci-omap: Don't finish_mrq() on a command error during tuning |
| |
| From: Faiz Abbas <faiz_abbas@ti.com> |
| |
| commit 5c41ea6d52003b5bc77c2a82fd5ca7d480237d89 upstream. |
| |
| commit 5b0d62108b46 ("mmc: sdhci-omap: Add platform specific reset |
| callback") skips data resets during tuning operation. Because of this, |
| a data error or data finish interrupt might still arrive after a command |
| error has been handled and the mrq ended. This ends up with a "mmc0: Got |
| data interrupt 0x00000002 even though no data operation was in progress" |
| error message. |
| |
| Fix this by adding a platform specific callback for sdhci_irq. Mark the |
| mrq as a failure but wait for a data interrupt instead of calling |
| finish_mrq(). |
| |
| Fixes: 5b0d62108b46 ("mmc: sdhci-omap: Add platform specific reset |
| callback") |
| Signed-off-by: Faiz Abbas <faiz_abbas@ti.com> |
| Acked-by: Adrian Hunter <adrian.hunter@intel.com> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/mmc/host/sdhci-omap.c | 38 ++++++++++++++++++++++++++++++++++++++ |
| 1 file changed, 38 insertions(+) |
| |
| --- a/drivers/mmc/host/sdhci-omap.c |
| +++ b/drivers/mmc/host/sdhci-omap.c |
| @@ -797,6 +797,43 @@ void sdhci_omap_reset(struct sdhci_host |
| sdhci_reset(host, mask); |
| } |
| |
| +#define CMD_ERR_MASK (SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX |\ |
| + SDHCI_INT_TIMEOUT) |
| +#define CMD_MASK (CMD_ERR_MASK | SDHCI_INT_RESPONSE) |
| + |
| +static u32 sdhci_omap_irq(struct sdhci_host *host, u32 intmask) |
| +{ |
| + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); |
| + struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); |
| + |
| + if (omap_host->is_tuning && host->cmd && !host->data_early && |
| + (intmask & CMD_ERR_MASK)) { |
| + |
| + /* |
| + * Since we are not resetting data lines during tuning |
| + * operation, data error or data complete interrupts |
| + * might still arrive. Mark this request as a failure |
| + * but still wait for the data interrupt |
| + */ |
| + if (intmask & SDHCI_INT_TIMEOUT) |
| + host->cmd->error = -ETIMEDOUT; |
| + else |
| + host->cmd->error = -EILSEQ; |
| + |
| + host->cmd = NULL; |
| + |
| + /* |
| + * Sometimes command error interrupts and command complete |
| + * interrupt will arrive together. Clear all command related |
| + * interrupts here. |
| + */ |
| + sdhci_writel(host, intmask & CMD_MASK, SDHCI_INT_STATUS); |
| + intmask &= ~CMD_MASK; |
| + } |
| + |
| + return intmask; |
| +} |
| + |
| static struct sdhci_ops sdhci_omap_ops = { |
| .set_clock = sdhci_omap_set_clock, |
| .set_power = sdhci_omap_set_power, |
| @@ -807,6 +844,7 @@ static struct sdhci_ops sdhci_omap_ops = |
| .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, |
| .reset = sdhci_omap_reset, |
| .set_uhs_signaling = sdhci_omap_set_uhs_signaling, |
| + .irq = sdhci_omap_irq, |
| }; |
| |
| static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) |