diff mbox

[RFC] mmc: tmio: fix tuning for stubborn cards

Message ID 20171011000814.21055-1-niklas.soderlund+renesas@ragnatech.se (mailing list archive)
State Superseded
Delegated to: Geert Uytterhoeven
Headers show

Commit Message

Niklas Söderlund Oct. 11, 2017, 12:08 a.m. UTC
The commit 43b0b361b0170030 ("mmc: tmio: always get number of taps")
changed the behavior of the tuning. Before the commit the SCC was only
enabled for the first tuning attempt (host->init_tuning(host)), if that
failed the hardware where reset and tuning retried. In the second
attempt the SCC where never configured and tuning would succeed for some
stubborn cards. This patch restore this behavior which allows a troubled
card I have to be used.

Without this patch:
sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
sh_mobile_sdhi ee100000.sd: Tuning procedure failed
mmc0: tuning execution failed: -110
mmc0: error -110 whilst initialising SD card
sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
sh_mobile_sdhi ee100000.sd: Tuning procedure failed
mmc0: tuning execution failed: -110
mmc0: error -110 whilst initialising SD card

With this patch:
sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
sh_mobile_sdhi ee100000.sd: Tuning procedure with SCC enabled failed, retry with SCC disabled
mmc0: new ultra high speed SDR50 SDHC card at address aaaa
mmcblk0: mmc0:aaaa SU04G 3.69 GiB
 mmcblk0: p1 p2

Fixes: 43b0b361b0170030 ("mmc: tmio: always get number of taps")
Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/mmc/host/tmio_mmc_core.c | 50 ++++++++++++++++++++++++++--------------
 1 file changed, 33 insertions(+), 17 deletions(-)

Hi Wolfram,

I'm pretty sure this is not a proper fix for the underlying problem, but 
at least it restores the previous behavior and get the card working. I 
mostly post this RFC to share my findings and so we have some code to 
try and help us figure out what really is happening here.

// Niklas

Comments

Simon Horman Oct. 11, 2017, 7:36 a.m. UTC | #1
On Wed, Oct 11, 2017 at 02:08:14AM +0200, Niklas Söderlund wrote:
> The commit 43b0b361b0170030 ("mmc: tmio: always get number of taps")
> changed the behavior of the tuning. Before the commit the SCC was only
> enabled for the first tuning attempt (host->init_tuning(host)), if that
> failed the hardware where reset and tuning retried. In the second
> attempt the SCC where never configured and tuning would succeed for some
> stubborn cards. This patch restore this behavior which allows a troubled
> card I have to be used.

Hi Wolfram,

Is tuning retried if the card is changed, f.e. ejected and a different card
inserted?
Simon Horman Oct. 11, 2017, 7:38 a.m. UTC | #2
On Wed, Oct 11, 2017 at 09:36:48AM +0200, Simon Horman wrote:
> On Wed, Oct 11, 2017 at 02:08:14AM +0200, Niklas Söderlund wrote:
> > The commit 43b0b361b0170030 ("mmc: tmio: always get number of taps")
> > changed the behavior of the tuning. Before the commit the SCC was only
> > enabled for the first tuning attempt (host->init_tuning(host)), if that
> > failed the hardware where reset and tuning retried. In the second
> > attempt the SCC where never configured and tuning would succeed for some
> > stubborn cards. This patch restore this behavior which allows a troubled
> > card I have to be used.
> 
> Hi Wolfram,

Sorry, Hi Niklas!

> 
> Is tuning retried if the card is changed, f.e. ejected and a different card
> inserted?
>
Wolfram Sang Oct. 11, 2017, 7:40 a.m. UTC | #3
On Wed, Oct 11, 2017 at 09:36:48AM +0200, Simon Horman wrote:
> On Wed, Oct 11, 2017 at 02:08:14AM +0200, Niklas Söderlund wrote:
> > The commit 43b0b361b0170030 ("mmc: tmio: always get number of taps")
> > changed the behavior of the tuning. Before the commit the SCC was only
> > enabled for the first tuning attempt (host->init_tuning(host)), if that
> > failed the hardware where reset and tuning retried. In the second
> > attempt the SCC where never configured and tuning would succeed for some
> > stubborn cards. This patch restore this behavior which allows a troubled
> > card I have to be used.
> 
> Hi Wolfram,
> 
> Is tuning retried if the card is changed, f.e. ejected and a different card
> inserted?

I haven't tried this patch yet. I work on finalizing the I2C DMA helper
patches currently. Let's hope this goes smooth, so I can check Niklas'
findings soon.
Niklas Söderlund Oct. 11, 2017, 8:35 a.m. UTC | #4
Hi Simon,

On 2017-10-11 09:36:48 +0200, Simon Horman wrote:
> On Wed, Oct 11, 2017 at 02:08:14AM +0200, Niklas Söderlund wrote:
> > The commit 43b0b361b0170030 ("mmc: tmio: always get number of taps")
> > changed the behavior of the tuning. Before the commit the SCC was only
> > enabled for the first tuning attempt (host->init_tuning(host)), if that
> > failed the hardware where reset and tuning retried. In the second
> > attempt the SCC where never configured and tuning would succeed for some
> > stubborn cards. This patch restore this behavior which allows a troubled
> > card I have to be used.
> 
> Hi Wolfram,
> 
> Is tuning retried if the card is changed, f.e. ejected and a different card
> inserted?

I'd say tuning is retried every time a card is inserted, based on my 
tests bellow. Which would make the change in 43b0b361b0170030 correct as 
the number of taps should be reread each time but the fallback to try 
tuning without the SCC clock changed restored (if that is correct 
behavior?). The register write which breaks my stubborn card tuning is 
in renesas_sdhi_init_tuning() in drivers/mmc/host/renesas_sdhi_core.c:

    # I assume this write is just to unlock writing to 
    # SH_MOBILE_SDHI_SCC_CKSEL ?
    sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, ~CLK_CTL_SCLKEN &
                    sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));

    # This register change starts to produce the timeout for CMD19 with 
    # my stubborn card. In renesas_sdhi_hw_reset() this register is 
    # reset and tuning then works.
    sd_scc_write32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL,
                   SH_MOBILE_SDHI_SCC_CKSEL_DTSEL |
                   sd_scc_read32(host, priv, SH_MOBILE_SDHI_SCC_CKSEL));

    # I as above assume this just locks the register write again ?
    sd_ctrl_write16(host, CTL_SD_CARD_CLK_CTL, CLK_CTL_SCLKEN |
                        sd_ctrl_read16(host, CTL_SD_CARD_CLK_CTL));

Test procedure as follows:

1. Insert stubborn card

[   29.048761] sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
[   34.168757] sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
[   34.228767] sh_mobile_sdhi ee100000.sd: Tuning procedure with SCC enabled failed, retry with SCC disabled
[   34.255636] mmc0: new ultra high speed SDR50 SDHC card at address aaaa
[   34.262440] mmcblk0: mmc0:aaaa SU04G 3.69 GiB 
[   34.274980]  mmcblk0: p1 p2

2. Eject stubborn card

[  115.858994] mmc0: card aaaa removed

3. Insert other card

[  137.195795] mmc0: new SD card at address 9749
[  137.200434] mmcblk0: mmc0:9749 SD128 120 MiB (ro)
[  137.208510]  mmcblk0: p1

4. Eject other card

[  142.499073] mmc0: card 9749 removed

5. Insert stubborn card

[  176.248760] sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
[  181.368756] sh_mobile_sdhi ee100000.sd: timeout waiting for hardware interrupt (CMD19)
[  181.428768] sh_mobile_sdhi ee100000.sd: Tuning procedure with SCC enabled failed, retry with SCC disabled
[  181.455631] mmc0: new ultra high speed SDR50 SDHC card at address aaaa
[  181.462424] mmcblk0: mmc0:aaaa SU04G 3.69 GiB 
[  181.474949]  mmcblk0: p1 p2
diff mbox

Patch

diff --git a/drivers/mmc/host/tmio_mmc_core.c b/drivers/mmc/host/tmio_mmc_core.c
index 12cf8288d6635eaf..e7e6a0f3f2610301 100644
--- a/drivers/mmc/host/tmio_mmc_core.c
+++ b/drivers/mmc/host/tmio_mmc_core.c
@@ -819,10 +819,35 @@  static void tmio_mmc_hw_reset(struct mmc_host *mmc)
 		host->hw_reset(host);
 }
 
+static int __tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
+{
+	struct tmio_mmc_host *host = mmc_priv(mmc);
+	unsigned int i;
+	int ret;
+
+	bitmap_zero(host->taps, host->tap_num * 2);
+
+	/* Issue CMD19 twice for each tap */
+	for (i = 0; i < 2 * host->tap_num; i++) {
+		if (host->prepare_tuning)
+			host->prepare_tuning(host, i % host->tap_num);
+
+		ret = mmc_send_tuning(mmc, opcode, NULL);
+		if (ret && ret != -EILSEQ)
+			return ret;
+		if (ret == 0)
+			set_bit(i, host->taps);
+
+		mdelay(1);
+	}
+
+	return host->select_tuning(host);
+}
+
 static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 {
 	struct tmio_mmc_host *host = mmc_priv(mmc);
-	int i, ret = 0;
+	int ret = 0;
 
 	if (!host->init_tuning || !host->select_tuning)
 		/* Tuning is not supported */
@@ -839,24 +864,15 @@  static int tmio_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
 		goto out;
 	}
 
-	bitmap_zero(host->taps, host->tap_num * 2);
-
-	/* Issue CMD19 twice for each tap */
-	for (i = 0; i < 2 * host->tap_num; i++) {
-		if (host->prepare_tuning)
-			host->prepare_tuning(host, i % host->tap_num);
-
-		ret = mmc_send_tuning(mmc, opcode, NULL);
-		if (ret && ret != -EILSEQ)
-			goto out;
-		if (ret == 0)
-			set_bit(i, host->taps);
-
-		mdelay(1);
+	ret = __tmio_mmc_execute_tuning(mmc, opcode);
+	if (ret) {
+		/* Tuning failed with SCC enabled, reset hardware and retry */
+		dev_info(&host->pdev->dev,
+			 "Tuning procedure with SCC enabled failed, retry with SCC disabled\n");
+		host->hw_reset(host);
+		ret = __tmio_mmc_execute_tuning(mmc, opcode);
 	}
 
-	ret = host->select_tuning(host);
-
 out:
 	if (ret < 0) {
 		dev_warn(&host->pdev->dev, "Tuning procedure failed\n");