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().
Unified · Split
| @@ -797,6 +797,43 @@ void sdhci_omap_reset(struct sdhci_host *host, u8 mask) · 796 unmodified lines | |||
| 797 | sdhci_reset(host, mask); | 797 | sdhci_reset(host, mask); |
| 798 | } | 798 | } |
| 799 | 799 | ||
| 800 | #define CMD_ERR_MASK (SDHCI_INT_CRC | SDHCI_INT_END_BIT | SDHCI_INT_INDEX |\ | ||
| 801 | SDHCI_INT_TIMEOUT) | ||
| 802 | #define CMD_MASK (CMD_ERR_MASK | SDHCI_INT_RESPONSE) | ||
| 803 | |||
| 804 | static u32 sdhci_omap_irq(struct sdhci_host *host, u32 intmask) | ||
| 805 | { | ||
| 806 | struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); | ||
| 807 | struct sdhci_omap_host *omap_host = sdhci_pltfm_priv(pltfm_host); | ||
| 808 | |||
| 809 | if (omap_host->is_tuning && host->cmd && !host->data_early && | ||
| 810 | (intmask & CMD_ERR_MASK)) { | ||
| 811 | |||
| 812 | /* | ||
| 813 | * Since we are not resetting data lines during tuning | ||
| 814 | * operation, data error or data complete interrupts | ||
| 815 | * might still arrive. Mark this request as a failure | ||
| 816 | * but still wait for the data interrupt | ||
| 817 | */ | ||
| 818 | if (intmask & SDHCI_INT_TIMEOUT) | ||
| 819 | host->cmd->error = -ETIMEDOUT; | ||
| 820 | else | ||
| 821 | host->cmd->error = -EILSEQ; | ||
| 822 | |||
| 823 | host->cmd = NULL; | ||
| 824 | |||
| 825 | /* | ||
| 826 | * Sometimes command error interrupts and command complete | ||
| 827 | * interrupt will arrive together. Clear all command related | ||
| 828 | * interrupts here. | ||
| 829 | */ | ||
| 830 | sdhci_writel(host, intmask & CMD_MASK, SDHCI_INT_STATUS); | ||
| 831 | intmask &= ~CMD_MASK; | ||
| 832 | } | ||
| 833 | |||
| 834 | return intmask; | ||
| 835 | } | ||
| 836 | |||
| 800 | static struct sdhci_ops sdhci_omap_ops = { | 837 | static struct sdhci_ops sdhci_omap_ops = { |
| 801 | .set_clock = sdhci_omap_set_clock, | 838 | .set_clock = sdhci_omap_set_clock, |
| 802 | .set_power = sdhci_omap_set_power, | 839 | .set_power = sdhci_omap_set_power, |
| @@ -807,6 +844,7 @@ static struct sdhci_ops sdhci_omap_ops = { · 4 unmodified lines | |||
| 807 | .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, | 844 | .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, |
| 808 | .reset = sdhci_omap_reset, | 845 | .reset = sdhci_omap_reset, |
| 809 | .set_uhs_signaling = sdhci_omap_set_uhs_signaling, | 846 | .set_uhs_signaling = sdhci_omap_set_uhs_signaling, |
| 847 | .irq = sdhci_omap_irq, | ||
| 810 | }; | 848 | }; |
| 811 | 849 | ||
| 812 | static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) | 850 | static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) |