mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH 2/2] [OLPC] sdhci: add quirk for the Marvell CaFe's interrupt timeout
@ 2008-06-27 20:24 Andres Salomon
  0 siblings, 0 replies; only message in thread
From: Andres Salomon @ 2008-06-27 20:24 UTC (permalink / raw)
  To: drzeus-sdhci; +Cc: sdhci-devel, linux-kernel, akpm

[Note that this is against Pierre's mmc/next branch]


The CaFe chip has a hardware bug that ends up with us getting a timeout
value that's too small, causing the following sorts of problems:

[   60.525138] mmcblk0: error -110 transferring data
[   60.531477] end_request: I/O error, dev mmcblk0, sector 1484353
[   60.533371] Buffer I/O error on device mmcblk0p2, logical block 181632
[   60.533371] lost page write due to I/O error on mmcblk0p2

To play it safe, we simply set the timeout to the max possible value
(0xE), and that works.  It also breaks the timeout calculation logic
out into a separate function.

Mitch verified that using 0xE instead of 0xC in OFW fixed timeout
problems for a user with an 8GB card, as well.

Signed-off-by: Andres Salomon <dilinger@debian.org>
---
 drivers/mmc/host/sdhci-pci.c |    3 +-
 drivers/mmc/host/sdhci.c     |   43 +++++++++++++++++++++++++++++------------
 drivers/mmc/host/sdhci.h     |    2 +
 3 files changed, 34 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index ec375b8..70c0c78 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -105,7 +105,8 @@ 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,
+	.quirks		= SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+			  SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 };
 
 static int jmicron_pmos(struct sdhci_pci_chip *chip, int on)
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 5f1c1bf..228457c 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -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 calculate_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 +
@@ -361,6 +357,27 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 		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 = calculate_timeout(host, data);
 	writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL);
 
 	if (host->flags & SDHCI_USE_DMA)
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 37ae056..7c30251 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -178,6 +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 provides an incorrect timeout value for transfers */
+#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL			(1<<10)
 
 	int			irq;		/* Device IRQ */
 	void __iomem *		ioaddr;		/* Mapped address */
-- 
1.5.5.3


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-06-27 20:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-06-27 20:24 [PATCH 2/2] [OLPC] sdhci: add quirk for the Marvell CaFe's interrupt timeout Andres Salomon

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®