Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: sdhci: Do not invert write-protect twice

mmc_of_parse() reads device property "wp-inverted" and sets
MMC_CAP2_RO_ACTIVE_HIGH if it is true. MMC_CAP2_RO_ACTIVE_HIGH is used
to invert a write-protect (AKA read-only) GPIO value.

sdhci_get_property() also reads "wp-inverted" and sets
SDHCI_QUIRK_INVERTED_WRITE_PROTECT which is used to invert the
write-protect value as well but also acts upon a value read out from the
SDHCI_PRESENT_STATE register.

Many drivers call both mmc_of_parse() and sdhci_get_property(),
so that both MMC_CAP2_RO_ACTIVE_HIGH and
SDHCI_QUIRK_INVERTED_WRITE_PROTECT will be set if the controller has
device property "wp-inverted".

Amend the logic in sdhci_check_ro() to allow for that possibility,
so that the write-protect value is not inverted twice.

Also do not invert the value if it is a negative error value. Note that
callers treat an error the same as not-write-protected, so the result is
functionally the same in that case.

Also do not invert the value if sdhci host operation ->get_ro() is used.
None of the users of that callback set SDHCI_QUIRK_INVERTED_WRITE_PROTECT
directly or indirectly, but two do call mmc_gpio_get_ro(), so leave it to
them to deal with that if they ever set SDHCI_QUIRK_INVERTED_WRITE_PROTECT
in the future.

Fixes: 6d5cd068ee59 ("mmc: sdhci: use WP GPIO in sdhci_check_ro()")
Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Cc: stable@vger.kernel.org
Link: https://lore.kernel.org/r/20240614080051.4005-2-adrian.hunter@intel.com
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Adrian Hunter and committed by
Ulf Hansson
fbd64f90 84bb8d8b

+15 -7
+15 -7
drivers/mmc/host/sdhci.c
··· 2515 2515 2516 2516 static int sdhci_check_ro(struct sdhci_host *host) 2517 2517 { 2518 + bool allow_invert = false; 2518 2519 unsigned long flags; 2519 2520 int is_readonly; 2520 2521 2521 2522 spin_lock_irqsave(&host->lock, flags); 2522 2523 2523 - if (host->flags & SDHCI_DEVICE_DEAD) 2524 + if (host->flags & SDHCI_DEVICE_DEAD) { 2524 2525 is_readonly = 0; 2525 - else if (host->ops->get_ro) 2526 + } else if (host->ops->get_ro) { 2526 2527 is_readonly = host->ops->get_ro(host); 2527 - else if (mmc_can_gpio_ro(host->mmc)) 2528 + } else if (mmc_can_gpio_ro(host->mmc)) { 2528 2529 is_readonly = mmc_gpio_get_ro(host->mmc); 2529 - else 2530 + /* Do not invert twice */ 2531 + allow_invert = !(host->mmc->caps2 & MMC_CAP2_RO_ACTIVE_HIGH); 2532 + } else { 2530 2533 is_readonly = !(sdhci_readl(host, SDHCI_PRESENT_STATE) 2531 2534 & SDHCI_WRITE_PROTECT); 2535 + allow_invert = true; 2536 + } 2532 2537 2533 2538 spin_unlock_irqrestore(&host->lock, flags); 2534 2539 2535 - /* This quirk needs to be replaced by a callback-function later */ 2536 - return host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT ? 2537 - !is_readonly : is_readonly; 2540 + if (is_readonly >= 0 && 2541 + allow_invert && 2542 + (host->quirks & SDHCI_QUIRK_INVERTED_WRITE_PROTECT)) 2543 + is_readonly = !is_readonly; 2544 + 2545 + return is_readonly; 2538 2546 } 2539 2547 2540 2548 #define SAMPLE_COUNT 5