[PATCH v5 4/4] mmc: dw_mmc: Do not wait for DTO in case of error
From: Mårten Lindahl <hidden>
Date: 2021-12-20 11:30:44
Also in:
linux-arm-kernel, linux-mmc, linux-samsung-soc
Subsystem:
multimedia card (mmc), secure digital (sd) and sdio subsystem, synopsys designware mmc/sd/sdio driver, the rest · Maintainers:
Ulf Hansson, Jaehoon Chung, Shawn Lin, Linus Torvalds
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 <redacted> --- v3: - Define DW_MMC_QUIRK_EXTENDED_TMOUT. - Implement DW_MMC_QUIRK_EXTENDED_TMOUT for the ARTPEC-8 SoC. drivers/mmc/host/dw_mmc-exynos.c | 5 +++++ drivers/mmc/host/dw_mmc.c | 9 +++++++++ drivers/mmc/host/dw_mmc.h | 5 +++++ 3 files changed, 19 insertions(+)
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 3914024cf415..ca5be4445ae0 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c@@ -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;
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index a7745e193afa..da09a06898c9 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c@@ -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);
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 0a85d05eaf12..7f1e38621d13 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h@@ -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
--
2.20.1