Ejecting a card during a write results in a bad controller state which
corrupts all writes to subsequently inserted cards.
Work around this by resetting the controller in the set_ios() POWER_OFF
handler.
Tested on DM355.
Signed-off-by: Jon Povey <[email protected]>
---
This patch is against 2.6.36, it does not include the latest SDIO patch
at least.
To reproduce this in the unpatched sources, write heavily to the card
and eject it during a write. Note that for the first few seconds of
"writing a file" nothing is actually written to the card, it is cached
by Linux.
In the broken state that results, if a card is reinserted, the effect
is as if an internal write FIFO has not been cleared and contains 2
extra bytes. Tests suggest this is not the documented 32-byte FIFO but
something beyond that.
All blocks appear on the card starting with the last two bytes of the
previous block write, then the remaining sector data; the last two
bytes overflow into the next written sector, etc.
Toggling MMCCTL.CMDRST,DATRST clears this condition. These are toggled
several times during the error handlers called when the card is ejected
during write, but it seems the bad state is entered at some point later.
set_ios(MMC_POWER_OFF) seems to consistently be called at the end of
the cleanup process before a newly-inserted card is accessed, putting
an extra controller reset in here gets rid of the problem - but I'm not
sure this is the right way to fix this, it has a workaround feel.
Comments sought.. thanks.
---
drivers/mmc/host/davinci_mmc.c | 12 ++++++++++--
1 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/mmc/host/davinci_mmc.c b/drivers/mmc/host/davinci_mmc.c
index 33d9f1b..e5ee1c1 100644
--- a/drivers/mmc/host/davinci_mmc.c
+++ b/drivers/mmc/host/davinci_mmc.c
@@ -795,6 +795,9 @@ static void calculate_clk_divider(struct mmc_host *mmc, struct mmc_ios *ios)
}
}
+static void
+davinci_abort_data(struct mmc_davinci_host *host, struct mmc_data *data);
+
static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct mmc_davinci_host *host = mmc_priv(mmc);
@@ -856,9 +859,14 @@ static void mmc_davinci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
}
if (lose)
dev_warn(mmc_dev(host->mmc), "powerup timeout\n");
- }
- /* FIXME on power OFF, reset things ... */
+ } else if (ios->power_mode == MMC_POWER_OFF) {
+
+ /* Controller maybe in bad state, e.g. card pulled while writing */
+ davinci_abort_data(host, NULL);
+
+ /* FIXME on power OFF, reset more things ...? */
+ }
}
static void
--
1.6.3.3