Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ee53ab5d authored by Pierre Ossman's avatar Pierre Ossman
Browse files

sdhci: make workaround for timeout bug more general



Give the quirk for broken timeout handling a better chance of handling
more controllers by simply classifying the system as broken and setting
a fixed value.

Signed-off-by: default avatarPierre Ossman <drzeus@drzeus.cx>
parent 22606405
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -98,7 +98,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = {

static const struct sdhci_pci_fixes sdhci_cafe = {
	.quirks		= SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
			  SDHCI_QUIRK_INCR_TIMEOUT_CONTROL,
			  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
};

static const struct sdhci_pci_fixes sdhci_jmicron = {
+30 −20
Original line number Diff line number Diff line
@@ -314,23 +314,19 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
	DBG("PIO transfer complete.\n");
}

static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
{
	u8 count;
	unsigned target_timeout, current_timeout;

	WARN_ON(host->data);

	if (data == NULL)
		return;

	/* Sanity checks */
	BUG_ON(data->blksz * data->blocks > 524288);
	BUG_ON(data->blksz > host->mmc->max_blk_size);
	BUG_ON(data->blocks > 65535);

	host->data = data;
	host->data_early = 0;
	/*
	 * If the host controller provides us with an incorrect timeout
	 * value, just skip the check and use 0xE.  The hardware may take
	 * longer to time out, but that's much better than having a too-short
	 * timeout value.
	 */
	if ((host->quirks & SDHCI_QUIRK_BROKEN_TIMEOUT_VAL))
		return 0xE;

	/* timeout in us */
	target_timeout = data->timeout_ns / 1000 +
@@ -355,19 +351,33 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
			break;
	}

	/*
	 * Compensate for an off-by-one error in the CaFe hardware; otherwise,
	 * a too-small count gives us interrupt timeouts.
	 */
	if ((host->quirks & SDHCI_QUIRK_INCR_TIMEOUT_CONTROL))
		count++;

	if (count >= 0xF) {
		printk(KERN_WARNING "%s: Too large timeout requested!\n",
			mmc_hostname(host->mmc));
		count = 0xE;
	}

	return count;
}

static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
{
	u8 count;

	WARN_ON(host->data);

	if (data == NULL)
		return;

	/* Sanity checks */
	BUG_ON(data->blksz * data->blocks > 524288);
	BUG_ON(data->blksz > host->mmc->max_blk_size);
	BUG_ON(data->blocks > 65535);

	host->data = data;
	host->data_early = 0;

	count = sdhci_calc_timeout(host, data);
	writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);

	if (host->flags & SDHCI_USE_DMA)
+2 −2
Original line number Diff line number Diff line
@@ -178,8 +178,8 @@ struct sdhci_host {
#define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<8)
/* Controller needs voltage and power writes to happen separately */
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<9)
/* Controller has an off-by-one issue with timeout value */
#define SDHCI_QUIRK_INCR_TIMEOUT_CONTROL		(1<<10)
/* Controller provides an incorrect timeout value for transfers */
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL			(1<<10)

	int			irq;		/* Device IRQ */
	void __iomem *		ioaddr;		/* Mapped address */