[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#485192: SDHCI hacks used on OLPC



Package: linux-2.6
Version: 2.6.26~rc4-1~experimental.1
Severity: normal

This diff was extracted from OLPC branch.  Without it, MMC cards are not
detected.

I'm not setting the patch tag since the last hunks look like a kludge
(specially the off-by-one thing).

Putting Andres Salomon on CC, as he probably knows about the reasons this
was added.

-- System Information:
Debian Release: lenny/sid
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: i386 (i586)

Kernel: Linux 2.6.26-rc4-486
Locale: LANG=ca_AD.UTF-8, LC_CTYPE=ca_AD.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 91ded3e..43a6c2b 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -237,6 +237,12 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
 		if (brq.data.blocks > card->host->max_blk_count)
 			brq.data.blocks = card->host->max_blk_count;
 
+		if (mmc_card_sd(card) && !card->host->ios.clock) {
+			printk(KERN_ERR "%s: I/O to stopped card\n",
+			       req->rq_disk->disk_name);
+			goto cmd_err;
+		}
+
 		/*
 		 * If the host doesn't support multiple block writes, force
 		 * block writes to single block. SD cards are excepted from
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 07c2048..9ac2c2b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -469,6 +469,12 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 			break;
 	}
 
+	/*
+	 * There's an off-by-one error in the hw that we need to
+	 * compensate for.
+	 */
+	count++;
+
 	if (count >= 0xF) {
 		printk(KERN_WARNING "%s: Too large timeout requested!\n",
 			mmc_hostname(host->mmc));
@@ -756,19 +762,17 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 	if (!(host->chip->quirks & SDHCI_QUIRK_SINGLE_POWER_WRITE))
 		writeb(0, host->ioaddr + SDHCI_POWER_CONTROL);
 
-	pwr = SDHCI_POWER_ON;
-
 	switch (1 << power) {
 	case MMC_VDD_165_195:
-		pwr |= SDHCI_POWER_180;
+		pwr = SDHCI_POWER_180;
 		break;
 	case MMC_VDD_29_30:
 	case MMC_VDD_30_31:
-		pwr |= SDHCI_POWER_300;
+		pwr = SDHCI_POWER_300;
 		break;
 	case MMC_VDD_32_33:
 	case MMC_VDD_33_34:
-		pwr |= SDHCI_POWER_330;
+		pwr = SDHCI_POWER_330;
 		break;
 	default:
 		BUG();
@@ -776,6 +780,10 @@ static void sdhci_set_power(struct sdhci_host *host, unsigned short power)
 
 	writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
 
+	pwr |= SDHCI_POWER_ON;
+
+	writeb(pwr, host->ioaddr + SDHCI_POWER_CONTROL);
+
 out:
 	host->power = power;
 }

Reply to: