[PATCH] mmc: sd: limit SD card power limit according to cards capabilities

Ulf Hansson ulf.hansson at linaro.org
Wed Jan 13 02:09:05 PST 2016


On 2 January 2016 at 11:06, Russell King <rmk+kernel at arm.linux.org.uk> wrote:
> The SD card specification allows cards to error out a SWITCH command
> where the requested function in a group is not supported.  The spec
> provides for a set of capabilities which indicate which functions are
> supported.
>
> In the case of the power limit, requesting an unsupported power level
> via the SWITCH command fails, resulting in the power level remaining at
> the power-on default of 0.72W, even though the host and card may support
> higher powers levels.
>
> This has been seen with SanDisk 8GB cards, which support the default
> 0.72W and 1.44W (200mA and 400mA) in combination with an iMX6 host,
> supporting up to 2.88W (800mA).  This currently causes us to try to set
> a power limit function value of '3' (2.88W) which the card errors out
> on, and thereby causes the power level to remain at 0.72W rather than
> the desired 1.44W.
>
> Arrange to limit the selected current limit by the capabilities reported
> by the card to avoid the SWITCH command failing.  Select the highest
> current limit that the host and card combination support.
>
> Signed-off-by: Russell King <rmk+kernel at arm.linux.org.uk>

Thanks, applied for fixes!

I also found a commit which most likely caused this being a
regression. I decided to add a fixes tag for it.
Even-though $subject patch doesn't apply cleanly on top that commit,
it's rather trivial to fix if someone wants it to be applied for an
old stable tree.

Fixes: a39ca6ae0a08 ("mmc: core: Simplify and fix for SD switch processing")

Kind regards
Uffe

> ---
> This is a bug fix, and as such needs merging into v4.4-rc and stable
> kernels.  There is probably more to come on this, as the SD simplified
> spec says that the power limit should be set _after_ switching to UHS
> mode:
>
> "In UHS-I mode, *after* selecting one of SDR50, SDR104 or DDR50 mode
>  by Function Group 1, host needs to change the Power Limit to enable
>  the card to operate in higher performance."
>
> However, unlike this patch, I have not (yet) seen any detrimental
> effects from setting this before.
>
>  drivers/mmc/core/sd.c | 20 ++++++++++++++++----
>  1 file changed, 16 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
> index 141eaa923e18..c4c6e4200d18 100644
> --- a/drivers/mmc/core/sd.c
> +++ b/drivers/mmc/core/sd.c
> @@ -329,6 +329,7 @@ static int mmc_read_switch(struct mmc_card *card)
>                 card->sw_caps.sd3_bus_mode = status[13];
>                 /* Driver Strengths supported by the card */
>                 card->sw_caps.sd3_drv_type = status[9];
> +               card->sw_caps.sd3_curr_limit = status[7] | status[6] << 8;
>         }
>
>  out:
> @@ -545,14 +546,25 @@ static int sd_set_current_limit(struct mmc_card *card, u8 *status)
>          * when we set current limit to 200ma, the card will draw 200ma, and
>          * when we set current limit to 400/600/800ma, the card will draw its
>          * maximum 300ma from the host.
> +        *
> +        * The above is incorrect: if we try to set a current limit that is
> +        * not supported by the card, the card can rightfully error out the
> +        * attempt, and remain at the default current limit.  This results
> +        * in a 300mA card being limited to 200mA even though the host
> +        * supports 800mA. Failures seen with SanDisk 8GB UHS cards with
> +        * an iMX6 host. --rmk
>          */
> -       if (max_current >= 800)
> +       if (max_current >= 800 &&
> +           card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_800)
>                 current_limit = SD_SET_CURRENT_LIMIT_800;
> -       else if (max_current >= 600)
> +       else if (max_current >= 600 &&
> +                card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_600)
>                 current_limit = SD_SET_CURRENT_LIMIT_600;
> -       else if (max_current >= 400)
> +       else if (max_current >= 400 &&
> +                card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_400)
>                 current_limit = SD_SET_CURRENT_LIMIT_400;
> -       else if (max_current >= 200)
> +       else if (max_current >= 200 &&
> +                card->sw_caps.sd3_curr_limit & SD_MAX_CURRENT_200)
>                 current_limit = SD_SET_CURRENT_LIMIT_200;
>
>         if (current_limit != SD_SET_CURRENT_NO_CHANGE) {
> --
> 2.1.0
>



More information about the linux-arm-kernel mailing list