Skip to content

Commit

Permalink
mmc: dw_mmc: Do not wait for DTO in case of error
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Mårten Lindahl authored and Ulf Hansson committed Dec 21, 2021
1 parent 25d5417 commit 1a6fe7b
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 0 deletions.
5 changes: 5 additions & 0 deletions drivers/mmc/host/dw_mmc-exynos.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions drivers/mmc/host/dw_mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 5 additions & 0 deletions drivers/mmc/host/dw_mmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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

Expand Down

0 comments on commit 1a6fe7b

Please sign in to comment.