diff mbox

[RESEND,RFC,v2] mmc: Change the max discard sectors and erase response if mmc host supports busy signalling

Message ID 54f75bccac6e6e49d87a5122ea670038b508b33c.1465808036.git.baolin.wang@linaro.org
State New
Headers show

Commit Message

(Exiting) Baolin Wang June 28, 2016, 7:25 a.m. UTC
When mmc host HW supports busy signalling (using R1B as response), We
shouldn't use 'host->max_busy_timeout' as the limitation when deciding
the max discard sectors that we tell the generic BLOCK layer about.
Instead, we should pick one preferred erase size as the max discard
sectors.

If the host controller supports busy signalling and the timeout for
the erase operation does not exceed the max_busy_timeout, we should
use R1B response. Or we need to prevent the host from doing hw busy
detection, which is done by converting to a R1 response instead.

Changes since v1:
  - Remove the 'MMC_CAP_WAIT_WHILE_BUSY' flag checking when deciding
    the max discard sectors.

Signed-off-by: Baolin Wang <baolin.wang@linaro.org>

---
 drivers/mmc/core/core.c |   47 +++++++++++++++++++++++++++++++++++++++--------
 1 file changed, 39 insertions(+), 8 deletions(-)

-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

(Exiting) Baolin Wang July 18, 2016, 11:17 a.m. UTC | #1
Hi Ulf,

On 28 June 2016 at 15:25, Baolin Wang <baolin.wang@linaro.org> wrote:
> When mmc host HW supports busy signalling (using R1B as response), We

> shouldn't use 'host->max_busy_timeout' as the limitation when deciding

> the max discard sectors that we tell the generic BLOCK layer about.

> Instead, we should pick one preferred erase size as the max discard

> sectors.

>

> If the host controller supports busy signalling and the timeout for

> the erase operation does not exceed the max_busy_timeout, we should

> use R1B response. Or we need to prevent the host from doing hw busy

> detection, which is done by converting to a R1 response instead.

>

> Changes since v1:

>   - Remove the 'MMC_CAP_WAIT_WHILE_BUSY' flag checking when deciding

>     the max discard sectors.

>

> Signed-off-by: Baolin Wang <baolin.wang@linaro.org>

> ---

>  drivers/mmc/core/core.c |   47 +++++++++++++++++++++++++++++++++++++++--------

>  1 file changed, 39 insertions(+), 8 deletions(-)

>

> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c

> index 8b4dfd4..edd43b1 100644

> --- a/drivers/mmc/core/core.c

> +++ b/drivers/mmc/core/core.c

> @@ -2060,7 +2060,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,

>                         unsigned int to, unsigned int arg)

>  {

>         struct mmc_command cmd = {0};

> -       unsigned int qty = 0;

> +       unsigned int qty = 0, busy_timeout = 0;

>         unsigned long timeout;

>         int err;

>

> @@ -2128,8 +2128,23 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,

>         memset(&cmd, 0, sizeof(struct mmc_command));

>         cmd.opcode = MMC_ERASE;

>         cmd.arg = arg;

> -       cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;

> -       cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);

> +       busy_timeout = mmc_erase_timeout(card, arg, qty);

> +       /*

> +        * If the host controller supports busy signalling and the timeout for

> +        * the erase operation does not exceed the max_busy_timeout, we should

> +        * use R1B response. Or we need to prevent the host from doing hw busy

> +        * detection, which is done by converting to a R1 response instead.

> +        */

> +       if ((card->host->max_busy_timeout &&

> +           busy_timeout > card->host->max_busy_timeout) ||

> +           !(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)) {

> +               cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;

> +               cmd.busy_timeout = 0;

> +       } else {

> +               cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;

> +               cmd.busy_timeout = busy_timeout;

> +       }

> +

>         err = mmc_wait_for_cmd(card->host, &cmd, 0);

>         if (err) {

>                 pr_err("mmc_erase: erase error %d, status %#x\n",

> @@ -2321,23 +2336,39 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,

>                                             unsigned int arg)

>  {

>         struct mmc_host *host = card->host;

> -       unsigned int max_discard, x, y, qty = 0, max_qty, timeout;

> +       unsigned int max_discard, x, y, qty = 0, max_qty, min_qty, timeout;

>         unsigned int last_timeout = 0;

>

> -       if (card->erase_shift)

> +       if (card->erase_shift) {

>                 max_qty = UINT_MAX >> card->erase_shift;

> -       else if (mmc_card_sd(card))

> +               min_qty = card->pref_erase >> card->erase_shift;

> +       } else if (mmc_card_sd(card)) {

>                 max_qty = UINT_MAX;

> -       else

> +               min_qty = card->pref_erase;

> +       } else {

>                 max_qty = UINT_MAX / card->erase_size;

> +               min_qty = card->pref_erase / card->erase_size;

> +       }

>

>         /* Find the largest qty with an OK timeout */

>         do {

>                 y = 0;

>                 for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {

>                         timeout = mmc_erase_timeout(card, arg, qty + x);

> -                       if (timeout > host->max_busy_timeout)

> +                       /*

> +                        * We should not only use 'host->max_busy_timeout' as

> +                        * the limitation when deciding the max discard sectors.

> +                        * We should set a balance value to improve the erase

> +                        * speed, and it can not get too long timeout at the

> +                        * same time.

> +                        *

> +                        * Here we set 'card->pref_erase' as the minimal discard

> +                        * sectors when deciding the max discard sectors.

> +                        */

> +                       if (qty + x > min_qty &&

> +                           timeout > host->max_busy_timeout)

>                                 break;

> +

>                         if (timeout < last_timeout)

>                                 break;

>                         last_timeout = timeout;

> --

> 1.7.9.5

>


Do you have any comments about this patch? Thanks.

-- 
Baolin.wang
Best Regards
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson July 18, 2016, 11:22 a.m. UTC | #2
On 18 July 2016 at 13:17, Baolin Wang <baolin.wang@linaro.org> wrote:
> Hi Ulf,

>

> On 28 June 2016 at 15:25, Baolin Wang <baolin.wang@linaro.org> wrote:

>> When mmc host HW supports busy signalling (using R1B as response), We

>> shouldn't use 'host->max_busy_timeout' as the limitation when deciding

>> the max discard sectors that we tell the generic BLOCK layer about.

>> Instead, we should pick one preferred erase size as the max discard

>> sectors.

>>

>> If the host controller supports busy signalling and the timeout for

>> the erase operation does not exceed the max_busy_timeout, we should

>> use R1B response. Or we need to prevent the host from doing hw busy

>> detection, which is done by converting to a R1 response instead.

>>

>> Changes since v1:

>>   - Remove the 'MMC_CAP_WAIT_WHILE_BUSY' flag checking when deciding

>>     the max discard sectors.

>>

>> Signed-off-by: Baolin Wang <baolin.wang@linaro.org>

>> ---

>>  drivers/mmc/core/core.c |   47 +++++++++++++++++++++++++++++++++++++++--------

>>  1 file changed, 39 insertions(+), 8 deletions(-)

>>

>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c

>> index 8b4dfd4..edd43b1 100644

>> --- a/drivers/mmc/core/core.c

>> +++ b/drivers/mmc/core/core.c

>> @@ -2060,7 +2060,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,

>>                         unsigned int to, unsigned int arg)

>>  {

>>         struct mmc_command cmd = {0};

>> -       unsigned int qty = 0;

>> +       unsigned int qty = 0, busy_timeout = 0;

>>         unsigned long timeout;

>>         int err;

>>

>> @@ -2128,8 +2128,23 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,

>>         memset(&cmd, 0, sizeof(struct mmc_command));

>>         cmd.opcode = MMC_ERASE;

>>         cmd.arg = arg;

>> -       cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;

>> -       cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);

>> +       busy_timeout = mmc_erase_timeout(card, arg, qty);

>> +       /*

>> +        * If the host controller supports busy signalling and the timeout for

>> +        * the erase operation does not exceed the max_busy_timeout, we should

>> +        * use R1B response. Or we need to prevent the host from doing hw busy

>> +        * detection, which is done by converting to a R1 response instead.

>> +        */

>> +       if ((card->host->max_busy_timeout &&

>> +           busy_timeout > card->host->max_busy_timeout) ||

>> +           !(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)) {

>> +               cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;

>> +               cmd.busy_timeout = 0;

>> +       } else {

>> +               cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;

>> +               cmd.busy_timeout = busy_timeout;

>> +       }

>> +

>>         err = mmc_wait_for_cmd(card->host, &cmd, 0);

>>         if (err) {

>>                 pr_err("mmc_erase: erase error %d, status %#x\n",

>> @@ -2321,23 +2336,39 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,

>>                                             unsigned int arg)

>>  {

>>         struct mmc_host *host = card->host;

>> -       unsigned int max_discard, x, y, qty = 0, max_qty, timeout;

>> +       unsigned int max_discard, x, y, qty = 0, max_qty, min_qty, timeout;

>>         unsigned int last_timeout = 0;

>>

>> -       if (card->erase_shift)

>> +       if (card->erase_shift) {

>>                 max_qty = UINT_MAX >> card->erase_shift;

>> -       else if (mmc_card_sd(card))

>> +               min_qty = card->pref_erase >> card->erase_shift;

>> +       } else if (mmc_card_sd(card)) {

>>                 max_qty = UINT_MAX;

>> -       else

>> +               min_qty = card->pref_erase;

>> +       } else {

>>                 max_qty = UINT_MAX / card->erase_size;

>> +               min_qty = card->pref_erase / card->erase_size;

>> +       }

>>

>>         /* Find the largest qty with an OK timeout */

>>         do {

>>                 y = 0;

>>                 for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {

>>                         timeout = mmc_erase_timeout(card, arg, qty + x);

>> -                       if (timeout > host->max_busy_timeout)

>> +                       /*

>> +                        * We should not only use 'host->max_busy_timeout' as

>> +                        * the limitation when deciding the max discard sectors.

>> +                        * We should set a balance value to improve the erase

>> +                        * speed, and it can not get too long timeout at the

>> +                        * same time.

>> +                        *

>> +                        * Here we set 'card->pref_erase' as the minimal discard

>> +                        * sectors when deciding the max discard sectors.

>> +                        */

>> +                       if (qty + x > min_qty &&

>> +                           timeout > host->max_busy_timeout)

>>                                 break;

>> +

>>                         if (timeout < last_timeout)

>>                                 break;

>>                         last_timeout = timeout;

>> --

>> 1.7.9.5

>>

>

> Do you have any comments about this patch? Thanks.


Sorry for the delay.

I will have a look asap!

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ulf Hansson July 19, 2016, 11:57 a.m. UTC | #3
On 13 June 2016 at 10:54, Baolin Wang <baolin.wang@linaro.org> wrote:
> When mmc host HW supports busy signalling (using R1B as response), We

> shouldn't use 'host->max_busy_timeout' as the limitation when deciding

> the max discard sectors that we tell the generic BLOCK layer about.

> Instead, we should pick one preferred erase size as the max discard

> sectors.

>

> If the host controller supports busy signalling and the timeout for

> the erase operation does not exceed the max_busy_timeout, we should

> use R1B response. Or we need to prevent the host from doing hw busy

> detection, which is done by converting to a R1 response instead.

>

> Changes since v1:

>   - Remove the 'MMC_CAP_WAIT_WHILE_BUSY' flag checking when deciding

>     the max discard sectors.

>

> Signed-off-by: Baolin Wang <baolin.wang@linaro.org>

> ---

>  drivers/mmc/core/core.c |   47 +++++++++++++++++++++++++++++++++++++++--------

>  1 file changed, 39 insertions(+), 8 deletions(-)

>

> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c

> index 8b4dfd4..edd43b1 100644

> --- a/drivers/mmc/core/core.c

> +++ b/drivers/mmc/core/core.c

> @@ -2060,7 +2060,7 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,

>                         unsigned int to, unsigned int arg)

>  {

>         struct mmc_command cmd = {0};

> -       unsigned int qty = 0;

> +       unsigned int qty = 0, busy_timeout = 0;

>         unsigned long timeout;

>         int err;

>

> @@ -2128,8 +2128,23 @@ static int mmc_do_erase(struct mmc_card *card, unsigned int from,

>         memset(&cmd, 0, sizeof(struct mmc_command));

>         cmd.opcode = MMC_ERASE;

>         cmd.arg = arg;

> -       cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;

> -       cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);

> +       busy_timeout = mmc_erase_timeout(card, arg, qty);

> +       /*

> +        * If the host controller supports busy signalling and the timeout for

> +        * the erase operation does not exceed the max_busy_timeout, we should

> +        * use R1B response. Or we need to prevent the host from doing hw busy

> +        * detection, which is done by converting to a R1 response instead.

> +        */

> +       if ((card->host->max_busy_timeout &&

> +           busy_timeout > card->host->max_busy_timeout) ||

> +           !(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)) {


sdhci uses the max_busy_timeout, but doesn't always use MMC_CAP_WAIT_WHILE_BUSY.
I have probably asked Adrian about this before, but right now I can't
recall why this is the case.

Anyway, I don't think we need to check MMC_CAP_WAIT_WHILE_BUSY at this point.

> +               cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;

> +               cmd.busy_timeout = 0;

> +       } else {

> +               cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;

> +               cmd.busy_timeout = busy_timeout;

> +       }

> +

>         err = mmc_wait_for_cmd(card->host, &cmd, 0);

>         if (err) {

>                 pr_err("mmc_erase: erase error %d, status %#x\n",


You also need to fix the loop for polling with CMD13 to get the card
status. In case of when R1B+MMC_CAP_WAIT_WHILE_BUSY is used, the
polling shall be avoided.

Moreover, the polling loop doesn't care about the earlier used
calculated erase timeout, but instead defaults to the
MMC_CORE_TIMEOUT_MS, this is wrong.

Finally, perhaps as an improvement step; I think we shall make use of
the host's ->card_busy() callback if implemented and when
R1B+MMC_CAP_WAIT_WHILE_BUSY isn't used. This in favour of issuing
CMD13 in the loop.

You can see the sequence in __mmc_switch(), we should apply this to
the erase case as well. Perhaps we can even split up some of the code
in __mmc_switch() to allow it to re-used for the erase case as well!?

> @@ -2321,23 +2336,39 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,

>                                             unsigned int arg)

>  {

>         struct mmc_host *host = card->host;

> -       unsigned int max_discard, x, y, qty = 0, max_qty, timeout;

> +       unsigned int max_discard, x, y, qty = 0, max_qty, min_qty, timeout;

>         unsigned int last_timeout = 0;

>

> -       if (card->erase_shift)

> +       if (card->erase_shift) {

>                 max_qty = UINT_MAX >> card->erase_shift;

> -       else if (mmc_card_sd(card))

> +               min_qty = card->pref_erase >> card->erase_shift;

> +       } else if (mmc_card_sd(card)) {

>                 max_qty = UINT_MAX;

> -       else

> +               min_qty = card->pref_erase;

> +       } else {

>                 max_qty = UINT_MAX / card->erase_size;

> +               min_qty = card->pref_erase / card->erase_size;

> +       }

>

>         /* Find the largest qty with an OK timeout */


This comment needs to be updated.

>         do {

>                 y = 0;

>                 for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {

>                         timeout = mmc_erase_timeout(card, arg, qty + x);

> -                       if (timeout > host->max_busy_timeout)

> +                       /*

> +                        * We should not only use 'host->max_busy_timeout' as

> +                        * the limitation when deciding the max discard sectors.

> +                        * We should set a balance value to improve the erase

> +                        * speed, and it can not get too long timeout at the

> +                        * same time.


I am not really sure I understand this comment. Could you try to
elaborate on what value that will be picked when the max_busy_timeout
isn't just as the limiter.

> +                        *

> +                        * Here we set 'card->pref_erase' as the minimal discard

> +                        * sectors when deciding the max discard sectors.

> +                        */

> +                       if (qty + x > min_qty &&

> +                           timeout > host->max_busy_timeout)

>                                 break;

> +

>                         if (timeout < last_timeout)

>                                 break;

>                         last_timeout = timeout;

> --

> 1.7.9.5

>


Again, sorry for the delay in response!

Kind regards
Uffe
--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 8b4dfd4..edd43b1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2060,7 +2060,7 @@  static int mmc_do_erase(struct mmc_card *card, unsigned int from,
 			unsigned int to, unsigned int arg)
 {
 	struct mmc_command cmd = {0};
-	unsigned int qty = 0;
+	unsigned int qty = 0, busy_timeout = 0;
 	unsigned long timeout;
 	int err;
 
@@ -2128,8 +2128,23 @@  static int mmc_do_erase(struct mmc_card *card, unsigned int from,
 	memset(&cmd, 0, sizeof(struct mmc_command));
 	cmd.opcode = MMC_ERASE;
 	cmd.arg = arg;
-	cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
-	cmd.busy_timeout = mmc_erase_timeout(card, arg, qty);
+	busy_timeout = mmc_erase_timeout(card, arg, qty);
+	/*
+	 * If the host controller supports busy signalling and the timeout for
+	 * the erase operation does not exceed the max_busy_timeout, we should
+	 * use R1B response. Or we need to prevent the host from doing hw busy
+	 * detection, which is done by converting to a R1 response instead.
+	 */
+	if ((card->host->max_busy_timeout &&
+	    busy_timeout > card->host->max_busy_timeout) ||
+	    !(card->host->caps & MMC_CAP_WAIT_WHILE_BUSY)) {
+		cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC;
+		cmd.busy_timeout = 0;
+	} else {
+		cmd.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+		cmd.busy_timeout = busy_timeout;
+	}
+
 	err = mmc_wait_for_cmd(card->host, &cmd, 0);
 	if (err) {
 		pr_err("mmc_erase: erase error %d, status %#x\n",
@@ -2321,23 +2336,39 @@  static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
 					    unsigned int arg)
 {
 	struct mmc_host *host = card->host;
-	unsigned int max_discard, x, y, qty = 0, max_qty, timeout;
+	unsigned int max_discard, x, y, qty = 0, max_qty, min_qty, timeout;
 	unsigned int last_timeout = 0;
 
-	if (card->erase_shift)
+	if (card->erase_shift) {
 		max_qty = UINT_MAX >> card->erase_shift;
-	else if (mmc_card_sd(card))
+		min_qty = card->pref_erase >> card->erase_shift;
+	} else if (mmc_card_sd(card)) {
 		max_qty = UINT_MAX;
-	else
+		min_qty = card->pref_erase;
+	} else {
 		max_qty = UINT_MAX / card->erase_size;
+		min_qty = card->pref_erase / card->erase_size;
+	}
 
 	/* Find the largest qty with an OK timeout */
 	do {
 		y = 0;
 		for (x = 1; x && x <= max_qty && max_qty - x >= qty; x <<= 1) {
 			timeout = mmc_erase_timeout(card, arg, qty + x);
-			if (timeout > host->max_busy_timeout)
+			/*
+			 * We should not only use 'host->max_busy_timeout' as
+			 * the limitation when deciding the max discard sectors.
+			 * We should set a balance value to improve the erase
+			 * speed, and it can not get too long timeout at the
+			 * same time.
+			 *
+			 * Here we set 'card->pref_erase' as the minimal discard
+			 * sectors when deciding the max discard sectors.
+			 */
+			if (qty + x > min_qty &&
+			    timeout > host->max_busy_timeout)
 				break;
+
 			if (timeout < last_timeout)
 				break;
 			last_timeout = timeout;