diff mbox

[5/6] mmc: sdhci: calculate max_discard_to dynamically for SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK

Message ID 1386680168-5227-6-git-send-email-b29396@freescale.com (mailing list archive)
State New, archived
Headers show

Commit Message

Aisheng Dong Dec. 10, 2013, 12:56 p.m. UTC
For host controllers using SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, since the card
clock is changed dynamically for different cards, it does not make sense
to use the maximum host clock to calculate max_discard_to which may lead
the max_discard_to to be much smaller than its capbility and affect the card
discard performance a lot.
e.g. the host clock is 200Mhz, but the card is working on 50Mhz. Then the
max_discard_to is only 1/4 of its real capbility.

In this patch, it uses the actual_clock to calculate the max_discard_to
dynamically as long as a new clock speed is set.

Tested with a high speed SDHC card shows:
Originally:
mmc1: new high speed SDHC card at address aaaa
mmc1: calculated max. discard sectors 49152 for timeout 1355 ms
Now:
mmc1: new high speed SDHC card at address aaaa
mmc1: calculated max. discard sectors 712704 for timeout 5422 ms
The max_discard_sectors will increase a lot which will also improve discard
performance a lot.

The one known limitation of this approach is that it does not cover the special
case for user changes the clock via sysfs, since the max_discard_to is only
initialised for one time during the mmc queue init.

Signed-off-by: Dong Aisheng <b29396@freescale.com>
---
 drivers/mmc/host/sdhci.c |   27 +++++++++++++++++++++------
 1 files changed, 21 insertions(+), 6 deletions(-)

Comments

Shawn Guo Dec. 11, 2013, 3:01 a.m. UTC | #1
On Tue, Dec 10, 2013 at 08:56:07PM +0800, Dong Aisheng wrote:
> For host controllers using SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, since the card
> clock is changed dynamically for different cards, it does not make sense
> to use the maximum host clock to calculate max_discard_to which may lead
> the max_discard_to to be much smaller than its capbility and affect the card
> discard performance a lot.
> e.g. the host clock is 200Mhz, but the card is working on 50Mhz. Then the
> max_discard_to is only 1/4 of its real capbility.
> 
> In this patch, it uses the actual_clock to calculate the max_discard_to
> dynamically as long as a new clock speed is set.
> 
> Tested with a high speed SDHC card shows:
> Originally:
> mmc1: new high speed SDHC card at address aaaa
> mmc1: calculated max. discard sectors 49152 for timeout 1355 ms
> Now:
> mmc1: new high speed SDHC card at address aaaa
> mmc1: calculated max. discard sectors 712704 for timeout 5422 ms
> The max_discard_sectors will increase a lot which will also improve discard
> performance a lot.
> 
> The one known limitation of this approach is that it does not cover the special
> case for user changes the clock via sysfs, since the max_discard_to is only
> initialised for one time during the mmc queue init.
> 
> Signed-off-by: Dong Aisheng <b29396@freescale.com>
> ---
>  drivers/mmc/host/sdhci.c |   27 +++++++++++++++++++++------
>  1 files changed, 21 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 4cc3bd6..9be8a79 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -1143,14 +1143,14 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
>  	unsigned long timeout;
>  
>  	if (clock && clock == host->clock)
> -		return;
> +		goto out;

I do not quite understand this change.  Why do we need to recalculate
max_discard_to if the clock does not change since the last time that
the function is called?

Shawn

>  
>  	host->mmc->actual_clock = 0;
>  
>  	if (host->ops->set_clock) {
>  		host->ops->set_clock(host, clock);
>  		if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
> -			return;
> +			goto out;
>  	}
>  
>  	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
> @@ -1249,6 +1249,19 @@ clock_set:
>  
>  out:
>  	host->clock = clock;
> +
> +	/* update timeout_clk and max_discard_to once the SDCLK is changed */
> +	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK && clock) {
> +		host->timeout_clk = host->mmc->actual_clock ?
> +					host->mmc->actual_clock / 1000 :
> +					host->clock / 1000;
> +		if (host->ops->get_max_timeout)
> +			host->mmc->max_discard_to =
> +					host->ops->get_max_timeout(host);
> +		else
> +			host->mmc->max_discard_to = (1 << 27) /
> +					host->timeout_clk;
> +	}
>  }
>  
>  static inline void sdhci_update_clock(struct sdhci_host *host)
> @@ -2939,10 +2952,12 @@ int sdhci_add_host(struct sdhci_host *host)
>  	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
>  		host->timeout_clk = mmc->f_max / 1000;
>  
> -	if (host->ops->get_max_timeout)
> -		mmc->max_discard_to = host->ops->get_max_timeout(host);
> -	else
> -		mmc->max_discard_to = (1 << 27) / host->timeout_clk;
> +	if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
> +		if (host->ops->get_max_timeout)
> +			mmc->max_discard_to = host->ops->get_max_timeout(host);
> +		else
> +			mmc->max_discard_to = (1 << 27) / host->timeout_clk;
> +	}
>  
>  	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
>  
> -- 
> 1.7.2.rc3
> 
>
Dong Aisheng Dec. 11, 2013, 3:13 a.m. UTC | #2
On Wed, Dec 11, 2013 at 11:01 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> On Tue, Dec 10, 2013 at 08:56:07PM +0800, Dong Aisheng wrote:
>> For host controllers using SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK, since the card
>> clock is changed dynamically for different cards, it does not make sense
>> to use the maximum host clock to calculate max_discard_to which may lead
>> the max_discard_to to be much smaller than its capbility and affect the card
>> discard performance a lot.
>> e.g. the host clock is 200Mhz, but the card is working on 50Mhz. Then the
>> max_discard_to is only 1/4 of its real capbility.
>>
>> In this patch, it uses the actual_clock to calculate the max_discard_to
>> dynamically as long as a new clock speed is set.
>>
>> Tested with a high speed SDHC card shows:
>> Originally:
>> mmc1: new high speed SDHC card at address aaaa
>> mmc1: calculated max. discard sectors 49152 for timeout 1355 ms
>> Now:
>> mmc1: new high speed SDHC card at address aaaa
>> mmc1: calculated max. discard sectors 712704 for timeout 5422 ms
>> The max_discard_sectors will increase a lot which will also improve discard
>> performance a lot.
>>
>> The one known limitation of this approach is that it does not cover the special
>> case for user changes the clock via sysfs, since the max_discard_to is only
>> initialised for one time during the mmc queue init.
>>
>> Signed-off-by: Dong Aisheng <b29396@freescale.com>
>> ---
>>  drivers/mmc/host/sdhci.c |   27 +++++++++++++++++++++------
>>  1 files changed, 21 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
>> index 4cc3bd6..9be8a79 100644
>> --- a/drivers/mmc/host/sdhci.c
>> +++ b/drivers/mmc/host/sdhci.c
>> @@ -1143,14 +1143,14 @@ static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
>>       unsigned long timeout;
>>
>>       if (clock && clock == host->clock)
>> -             return;
>> +             goto out;
>
> I do not quite understand this change.  Why do we need to recalculate
> max_discard_to if the clock does not change since the last time that
> the function is called?
>

Good catch.
It's safe to return directly here.
Will update in v2.

Regards
Dong Aisheng

> Shawn
>
>>
>>       host->mmc->actual_clock = 0;
>>
>>       if (host->ops->set_clock) {
>>               host->ops->set_clock(host, clock);
>>               if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
>> -                     return;
>> +                     goto out;
>>       }
>>
>>       sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
>> @@ -1249,6 +1249,19 @@ clock_set:
>>
>>  out:
>>       host->clock = clock;
>> +
>> +     /* update timeout_clk and max_discard_to once the SDCLK is changed */
>> +     if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK && clock) {
>> +             host->timeout_clk = host->mmc->actual_clock ?
>> +                                     host->mmc->actual_clock / 1000 :
>> +                                     host->clock / 1000;
>> +             if (host->ops->get_max_timeout)
>> +                     host->mmc->max_discard_to =
>> +                                     host->ops->get_max_timeout(host);
>> +             else
>> +                     host->mmc->max_discard_to = (1 << 27) /
>> +                                     host->timeout_clk;
>> +     }
>>  }
>>
>>  static inline void sdhci_update_clock(struct sdhci_host *host)
>> @@ -2939,10 +2952,12 @@ int sdhci_add_host(struct sdhci_host *host)
>>       if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
>>               host->timeout_clk = mmc->f_max / 1000;
>>
>> -     if (host->ops->get_max_timeout)
>> -             mmc->max_discard_to = host->ops->get_max_timeout(host);
>> -     else
>> -             mmc->max_discard_to = (1 << 27) / host->timeout_clk;
>> +     if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
>> +             if (host->ops->get_max_timeout)
>> +                     mmc->max_discard_to = host->ops->get_max_timeout(host);
>> +             else
>> +                     mmc->max_discard_to = (1 << 27) / host->timeout_clk;
>> +     }
>>
>>       mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
>>
>> --
>> 1.7.2.rc3
>>
>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Shawn Guo Dec. 11, 2013, 4:05 a.m. UTC | #3
On Tue, Dec 10, 2013 at 08:56:07PM +0800, Dong Aisheng wrote:
>  static inline void sdhci_update_clock(struct sdhci_host *host)
> @@ -2939,10 +2952,12 @@ int sdhci_add_host(struct sdhci_host *host)
>  	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
>  		host->timeout_clk = mmc->f_max / 1000;

Since max_discard_to calculation below will not happen for
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK case, does it still make sense to
keep the above code?

Or put it in the other way, if we keep the above code and do not make
the change below, will there be any problem besides the max_discard_to
initialization plays for nothing?

All in all, I'm just confused why we keep the above code and make the
change below at the same time.

Shawn

>  
> -	if (host->ops->get_max_timeout)
> -		mmc->max_discard_to = host->ops->get_max_timeout(host);
> -	else
> -		mmc->max_discard_to = (1 << 27) / host->timeout_clk;
> +	if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
> +		if (host->ops->get_max_timeout)
> +			mmc->max_discard_to = host->ops->get_max_timeout(host);
> +		else
> +			mmc->max_discard_to = (1 << 27) / host->timeout_clk;
> +	}
>  
>  	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
>  
> -- 
> 1.7.2.rc3
> 
>
Dong Aisheng Dec. 11, 2013, 5:06 a.m. UTC | #4
On Wed, Dec 11, 2013 at 12:05 PM, Shawn Guo <shawn.guo@linaro.org> wrote:
> On Tue, Dec 10, 2013 at 08:56:07PM +0800, Dong Aisheng wrote:
>>  static inline void sdhci_update_clock(struct sdhci_host *host)
>> @@ -2939,10 +2952,12 @@ int sdhci_add_host(struct sdhci_host *host)
>>       if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
>>               host->timeout_clk = mmc->f_max / 1000;
>
> Since max_discard_to calculation below will not happen for
> SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK case, does it still make sense to
> keep the above code?
>

Right, i missed to remove it.
Will update in v2.

> Or put it in the other way, if we keep the above code and do not make
> the change below, will there be any problem besides the max_discard_to
> initialization plays for nothing?
>
> All in all, I'm just confused why we keep the above code and make the
> change below at the same time.
>

THe max_discard_to should be dynamically updated for
SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK
when changing the clock, so we can remove above lines.

Regards
Dong Aisheng

> Shawn
>
>>
>> -     if (host->ops->get_max_timeout)
>> -             mmc->max_discard_to = host->ops->get_max_timeout(host);
>> -     else
>> -             mmc->max_discard_to = (1 << 27) / host->timeout_clk;
>> +     if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
>> +             if (host->ops->get_max_timeout)
>> +                     mmc->max_discard_to = host->ops->get_max_timeout(host);
>> +             else
>> +                     mmc->max_discard_to = (1 << 27) / host->timeout_clk;
>> +     }
>>
>>       mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;
>>
>> --
>> 1.7.2.rc3
>>
>>
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
diff mbox

Patch

diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index 4cc3bd6..9be8a79 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -1143,14 +1143,14 @@  static void sdhci_set_clock(struct sdhci_host *host, unsigned int clock)
 	unsigned long timeout;
 
 	if (clock && clock == host->clock)
-		return;
+		goto out;
 
 	host->mmc->actual_clock = 0;
 
 	if (host->ops->set_clock) {
 		host->ops->set_clock(host, clock);
 		if (host->quirks & SDHCI_QUIRK_NONSTANDARD_CLOCK)
-			return;
+			goto out;
 	}
 
 	sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL);
@@ -1249,6 +1249,19 @@  clock_set:
 
 out:
 	host->clock = clock;
+
+	/* update timeout_clk and max_discard_to once the SDCLK is changed */
+	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK && clock) {
+		host->timeout_clk = host->mmc->actual_clock ?
+					host->mmc->actual_clock / 1000 :
+					host->clock / 1000;
+		if (host->ops->get_max_timeout)
+			host->mmc->max_discard_to =
+					host->ops->get_max_timeout(host);
+		else
+			host->mmc->max_discard_to = (1 << 27) /
+					host->timeout_clk;
+	}
 }
 
 static inline void sdhci_update_clock(struct sdhci_host *host)
@@ -2939,10 +2952,12 @@  int sdhci_add_host(struct sdhci_host *host)
 	if (host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)
 		host->timeout_clk = mmc->f_max / 1000;
 
-	if (host->ops->get_max_timeout)
-		mmc->max_discard_to = host->ops->get_max_timeout(host);
-	else
-		mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+	if (!(host->quirks & SDHCI_QUIRK_DATA_TIMEOUT_USES_SDCLK)) {
+		if (host->ops->get_max_timeout)
+			mmc->max_discard_to = host->ops->get_max_timeout(host);
+		else
+			mmc->max_discard_to = (1 << 27) / host->timeout_clk;
+	}
 
 	mmc->caps |= MMC_CAP_SDIO_IRQ | MMC_CAP_ERASE | MMC_CAP_CMD23;