Commit 1a6fe7bb authored by Mårten Lindahl's avatar Mårten Lindahl Committed by Ulf Hansson
Browse files

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: default avatarMårten Lindahl <marten.lindahl@axis.com>
Link: https://lore.kernel.org/r/20211220113026.21129-5-marten.lindahl@axis.com


Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
parent 25d5417a
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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;
+9 −0
Original line number Diff line number Diff line
@@ -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);
+5 −0
Original line number Diff line number Diff line
@@ -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