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: