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 | 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 | 837 | static struct sdhci_ops sdhci_omap_ops = { |
| 801 | 838 | .set_clock = sdhci_omap_set_clock, |
| 802 | 839 | .set_power = sdhci_omap_set_power, |
| @@ -807,6 +844,7 @@ static struct sdhci_ops sdhci_omap_ops = { · 4 unmodified lines | ||
| 807 | 844 | .platform_send_init_74_clocks = sdhci_omap_init_74_clocks, |
| 808 | 845 | .reset = sdhci_omap_reset, |
| 809 | 846 | .set_uhs_signaling = sdhci_omap_set_uhs_signaling, |
| 847 | + .irq = sdhci_omap_irq, | |
| 810 | 848 | }; |
| 811 | 849 | |
| 812 | 850 | static int sdhci_omap_set_capabilities(struct sdhci_omap_host *omap_host) |