Skip to contentSkip to conversation

mmc: sdhci: use udelay instead of mdelay for some cases

PATCH In review Shawn.Dong 3 participants 6 messages Oct 27, 2011 – Nov 4, 2011

Subsystems (2)
lore
Share & tools
lore

Shawn.Dong

author
#0 lore raw

PATCH 1/1 mmc: sdhci: use udelay instead of mdelay for some cases

sdhci_set_clock or sdhci_reset or sdhci_send_command may be used in critical region which is protected by spin_lock_irqsave. Thus, these functions will delay the responsing of the kernel interrupts.

So in this case, using a mdelay will cause unnecessary latency. Our hardware, in most case will not cause 1ms to finish its job. Using udelay instead can reduce it.

By default, sdhci_do_set_ios will need about 1ms to finish in my platform. After using udelay instead, sdhci_do_set_ios only need a few microseconds.

---
 drivers/mmc/host/sdhci.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)
drivers/mmc/host/sdhci.c +6 -6
index 6d8eea3..9314cd1 100644
@@ -195,7 +195,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 		host->clock = 0;
 
 	/* Wait max 100 ms */
-	timeout = 100;
+	timeout = 10000;
 
 	/* hw clears the bit when it's done */
 	while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
@@ -206,7 +206,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
 			return;
 		}
 		timeout--;
-		mdelay(1);
+		udelay(10);
 	}
 
 	if (host->ops->platform_reset_exit)
@@ -959,7 +959,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 	WARN_ON(host->cmd);
 
 	/* Wait max 10 ms */
-	timeout = 10;
+	timeout = 1000;
 
 	mask = SDHCI_CMD_INHIBIT;
 	if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
@@ -980,7 +980,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
 			return;
 		}
 		timeout--;
-		mdelay(1);
+		udelay(10);
 	}
 
 	mod_timer(&host->timer, jiffies + 10 * HZ);
@@ -1140,7 +1140,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 	sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
 	/* Wait max 20 ms */
-	timeout = 20;
+	timeout = 2000;
 	while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
 		& SDHCI_CLOCK_INT_STABLE)) {
 		if (timeout == 0) {
@@ -1150,7 +1150,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 			return;
 		}
 		timeout--;
-		mdelay(1);
+		udelay(10);
 	}
 
 	clk |= SDHCI_CLOCK_CARD_EN;
Signature · 1 line
1.7.3.4
#1 lore raw

2011/10/27 Shawn.Dong <[email protected]>:

Quoted 4 lines

sdhci_set_clock or sdhci_reset or sdhci_send_command may be used in critical region which is protected by spin_lock_irqsave. Thus, these functions will delay the responsing of the kernel interrupts.

Quoted 8 lines

So in this case, using a mdelay will cause unnecessary latency. Our hardware, in most case will not cause 1ms to finish its job. Using udelay instead can reduce it.

By default, sdhci_do_set_ios will need about 1ms to finish in my platform. After using udelay instead, sdhci_do_set_ios only need a few microseconds.

ACK, see my patch as well:
http://www.spinics.net/lists/linux-mmc/msg10257.html

Quoted 63 lines

---
 drivers/mmc/host/sdhci.c |   12 ++++++------

 1 files changed, 6 insertions(+), 6 deletions(-)
drivers/mmc/host/sdhci.c +6 -7
index 6d8eea3..9314cd1 100644
@@ -195,7 +195,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
                host->clock = 0;
 
        /* Wait max 100 ms */
-       timeout = 100;
+       timeout = 10000;
 
        /* hw clears the bit when it's done */
        while (sdhci_readb(host, SDHCI_SOFTWARE_RESET) & mask) {
@@ -206,7 +206,7 @@ static void sdhci_reset(struct sdhci_host *host, u8 mask)
                        return;
                }
                timeout--;
-               mdelay(1);
+               udelay(10);
        }
 
        if (host->ops->platform_reset_exit)
@@ -959,7 +959,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
        WARN_ON(host->cmd);
 
        /* Wait max 10 ms */
-       timeout = 10;
+       timeout = 1000;
 
        mask = SDHCI_CMD_INHIBIT;
        if ((cmd->data != NULL) || (cmd->flags & MMC_RSP_BUSY))
@@ -980,7 +980,7 @@ static void sdhci_send_command(struct sdhci_host *host, struct mmc_command *cmd)
                        return;
                }
                timeout--;
-               mdelay(1);
+               udelay(10);
        }
 
        mod_timer(&host->timer, jiffies + 10 * HZ);
@@ -1140,7 +1140,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
        sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
 
        /* Wait max 20 ms */
-       timeout = 20;
+       timeout = 2000;
        while (!((clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL))
                & SDHCI_CLOCK_INT_STABLE)) {
                if (timeout == 0) {
@@ -1150,7 +1150,7 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
                        return;
                }
                timeout--;
-               mdelay(1);
+               udelay(10);
        }
 
        clk |= SDHCI_CLOCK_CARD_EN;
--
Quoted 1 line

1.7.3.4

-barry

#2 lore raw
In reply to Shawn.Dong

Hi,

Quoted 3 lines · Shawn.Dong

sdhci_set_clock or sdhci_reset or sdhci_send_command may be used in critical region which is protected by spin_lock_irqsave. Thus, these functions will delay the responsing of the kernel interrupts.

Yes, so this needs to be improved, not the delay values.

Quoted 3 lines

So in this case, using a mdelay will cause unnecessary latency. Our hardware, in most case will not cause 1ms to finish its job. Using udelay instead can reduce it.

Could you guarantee this for all other SDHCI hardware out there as well?

Regards,

Wolfram

Signature · 2 lines
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
author
#3 lore raw
Quoted 7 lines · Wolfram Sang

Hi,

Quoted 3 lines · Shawn.Dong

sdhci_set_clock or sdhci_reset or sdhci_send_command may be used in critical region which is protected by spin_lock_irqsave. Thus, these functions will delay the responsing of the kernel interrupts.

Quoted 7 lines

Yes, so this needs to be improved, not the delay values.

Quoted 3 lines

So in this case, using a mdelay will cause unnecessary latency. Our hardware, in most case will not cause 1ms to finish its job. Using udelay instead can reduce it.

Could you guarantee this for all other SDHCI hardware out there as well?

Even there are some SDHCI hardwares cannot be stable in microseconds, I think this is also OK since they just need to wait for a few more loops. The total waiting time is the same as before.

For the SDHCI hardware which need less time to be stable, this patch can improve performance for them.

Thanks
Shawn

#4 lore raw
Quoted 4 lines

Even there are some SDHCI hardwares cannot be stable in microseconds, I think this is also OK since they just need to wait for a few more loops. The total waiting time is the same as before.

Well, I still think this is curing the symptoms not the cause. But will talk with Chris about it since we are both in Prague at the moment...

Signature · 2 lines
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
author
#5 lore raw
Quoted 7 lines · Wolfram Sang
Quoted 4 lines

Even there are some SDHCI hardwares cannot be stable in microseconds, I think this is also OK since they just need to wait for a few more loops. The total waiting time is the same as before.

Well, I still think this is curing the symptoms not the cause. But will talk with Chris about it since we are both in Prague at the moment...

Hi Wolfram & Chris,

This issue was found by using ftrace to track the irqsoff latency. Each time to call mmc_power_off, the latency is about 1ms on my platform. And this 1ms delay is causing by the mdelay(1) in _set_ios.

You know, after changing some register like CLOCK_CONTROL or RESET, driver will start to check them every 1ms since we are using mdelay(1). For some devices, it needn't software to wait for 1ms, but only some milliseconds. So I think change to use udelay() is much better for those devices.

How do you think? Can you give some of your advice? Thank you.

Best Regards
Shawn