mmc: dw_mmc: Do not wait for DTO in case of error
authorMårten Lindahl <marten.lindahl@axis.com>
Mon, 20 Dec 2021 11:30:26 +0000 (12:30 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Tue, 21 Dec 2021 12:28:41 +0000 (13:28 +0100)
When running the ARTPEC-8 DWMMC IP version, and a data error interrupt
comes during a data read transfer, there is no guarantee for the data
transfer over interrupt (DTO) to come within the specified data timeout.
This case is handled by the dto_timer handler which will complete the
request with the comment:

 /*
  * If DTO interrupt does NOT come in sending data state,
  * we should notify the driver to terminate current transfer
  * and report a data timeout to the core.
  */

But since the ARTPEC-8 DWMMC IP version, supports an extended TMOUT
register which allows longer timeouts than the non ARTPEC-8 version
does, waiting for the dto_timer to complete the request in error cases
may cause the request to take significantly longer time than necessary.
This is specifically true for the failing steps during tuning of a
device.

Fix this by completing the request when the error interrupt comes. Since
this fix is specific for the ARTPEC-8, a quirk is added.

Signed-off-by: Mårten Lindahl <marten.lindahl@axis.com>
Link: https://lore.kernel.org/r/20211220113026.21129-5-marten.lindahl@axis.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
drivers/mmc/host/dw_mmc-exynos.c
drivers/mmc/host/dw_mmc.c
drivers/mmc/host/dw_mmc.h

index 3914024cf4152470cd4e9deaa3a702ad3aea6976..ca5be4445ae0591eecced69bd16f49ac2aa86860 100644 (file)
@@ -127,6 +127,11 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
                                DQS_CTRL_GET_RD_DELAY(priv->saved_strobe_ctrl);
        }
 
+       if (priv->ctrl_type == DW_MCI_TYPE_ARTPEC8) {
+               /* Quirk needed for the ARTPEC-8 SoC */
+               host->quirks |= DW_MMC_QUIRK_EXTENDED_TMOUT;
+       }
+
        host->bus_hz /= (priv->ciu_div + 1);
 
        return 0;
index 05b72b3c5dc0fdaacd58503d0c9e8580d61f5b4c..42bf8a2287ba7a0deabc71c0969435fd4239f61f 100644 (file)
@@ -2762,11 +2762,20 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
                if (pending & DW_MCI_DATA_ERROR_FLAGS) {
                        spin_lock(&host->irq_lock);
 
+                       if (host->quirks & DW_MMC_QUIRK_EXTENDED_TMOUT)
+                               del_timer(&host->dto_timer);
+
                        /* if there is an error report DATA_ERROR */
                        mci_writel(host, RINTSTS, DW_MCI_DATA_ERROR_FLAGS);
                        host->data_status = pending;
                        smp_wmb(); /* drain writebuffer */
                        set_bit(EVENT_DATA_ERROR, &host->pending_events);
+
+                       if (host->quirks & DW_MMC_QUIRK_EXTENDED_TMOUT)
+                               /* In case of error, we cannot expect a DTO */
+                               set_bit(EVENT_DATA_COMPLETE,
+                                       &host->pending_events);
+
                        tasklet_schedule(&host->tasklet);
 
                        spin_unlock(&host->irq_lock);
index 0a85d05eaf12bd223c88a883b7bf54b46e312a3b..7f1e38621d132296c4084fe4d4dceffa94fc37e8 100644 (file)
@@ -118,6 +118,7 @@ struct dw_mci_dma_slave {
  * @part_buf: Simple buffer for partial fifo reads/writes.
  * @push_data: Pointer to FIFO push function.
  * @pull_data: Pointer to FIFO pull function.
+ * @quirks: Set of quirks that apply to specific versions of the IP.
  * @vqmmc_enabled: Status of vqmmc, should be true or false.
  * @irq_flags: The flags to be passed to request_irq.
  * @irq: The irq value to be passed to request_irq.
@@ -223,6 +224,7 @@ struct dw_mci {
        void (*push_data)(struct dw_mci *host, void *buf, int cnt);
        void (*pull_data)(struct dw_mci *host, void *buf, int cnt);
 
+       u32                     quirks;
        bool                    vqmmc_enabled;
        unsigned long           irq_flags; /* IRQ flags */
        int                     irq;
@@ -274,6 +276,9 @@ struct dw_mci_board {
        struct dma_pdata *data;
 };
 
+/* Support for longer data read timeout */
+#define DW_MMC_QUIRK_EXTENDED_TMOUT            BIT(0)
+
 #define DW_MMC_240A            0x240a
 #define DW_MMC_280A            0x280a