mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-29 13:53:33 +00:00
mmc: dw_mmc: Do not wait for DTO in case of error
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>
This commit is contained in:
parent
25d5417a90
commit
1a6fe7bbc7
3 changed files with 19 additions and 0 deletions
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue