From: Phil Elwell Date: Wed, 11 May 2016 11:50:33 +0000 (+0100) Subject: mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards X-Git-Tag: archive/raspbian/4.9.51-1+rpi1~5^2~497 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=1fb32915e3e92ffe2ddb7bd6bcc26463c0019f97;p=linux-4.9.git mmc: Add MMC_QUIRK_ERASE_BROKEN for some cards Some SD cards have been found that corrupt data when small blocks are erased. Add a quirk to indicate that ERASE should not be used, and set it for cards of that type. Signed-off-by: Phil Elwell mmc: Apply QUIRK_BROKEN_ERASE to other capacities Signed-off-by: Phil Elwell mmc: Add card_quirks module parameter, log quirks Use mmc_block.card_quirks to override the quirks for all SD or MMC cards. The value is a bitfield using the bit positions defined in include/linux/mmc/card.h. If the module parameter is placed in the kernel command line (or bootargs) stored on the card then, assuming the device only has one SD card interface, the override effectively becomes card-specific. Signed-off-by: Phil Elwell --- diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 709a872ed484..894c105be9ce 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -135,6 +135,13 @@ enum { module_param(perdev_minors, int, 0444); MODULE_PARM_DESC(perdev_minors, "Minors numbers to allocate per device"); +/* + * Allow quirks to be overridden for the current card + */ +static char *card_quirks; +module_param(card_quirks, charp, 0644); +MODULE_PARM_DESC(card_quirks, "Force the use of the indicated quirks (a bitfield)"); + static inline int mmc_blk_part_switch(struct mmc_card *card, struct mmc_blk_data *md); static int get_card_status(struct mmc_card *card, u32 *status, int retries); @@ -2573,6 +2580,17 @@ static const struct mmc_fixup blk_fixups[] = MMC_FIXUP("V10016", CID_MANFID_KINGSTON, CID_OEMID_ANY, add_quirk_mmc, MMC_QUIRK_TRIM_BROKEN), + /* + * On some Kingston SD cards, multiple erases of less than 64 + * sectors can cause corruption. + */ + MMC_FIXUP("SD16G", 0x41, 0x3432, add_quirk_mmc, + MMC_QUIRK_ERASE_BROKEN), + MMC_FIXUP("SD32G", 0x41, 0x3432, add_quirk_mmc, + MMC_QUIRK_ERASE_BROKEN), + MMC_FIXUP("SD64G", 0x41, 0x3432, add_quirk_mmc, + MMC_QUIRK_ERASE_BROKEN), + END_FIXUP }; @@ -2580,6 +2598,7 @@ static int mmc_blk_probe(struct mmc_card *card) { struct mmc_blk_data *md, *part_md; char cap_str[10]; + char quirk_str[24]; /* * Check that the card supports the command class(es) we need. @@ -2587,7 +2606,16 @@ static int mmc_blk_probe(struct mmc_card *card) if (!(card->csd.cmdclass & CCC_BLOCK_READ)) return -ENODEV; - mmc_fixup_device(card, blk_fixups); + if (card_quirks) { + unsigned long quirks; + if (kstrtoul(card_quirks, 0, &quirks) == 0) + card->quirks = (unsigned int)quirks; + else + pr_err("mmc_block: Invalid card_quirks parameter '%s'\n", + card_quirks); + } + else + mmc_fixup_device(card, blk_fixups); md = mmc_blk_alloc(card); if (IS_ERR(md)) @@ -2595,9 +2623,14 @@ static int mmc_blk_probe(struct mmc_card *card) string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2, cap_str, sizeof(cap_str)); - pr_info("%s: %s %s %s %s\n", + if (card->quirks) + snprintf(quirk_str, sizeof(quirk_str), + " (quirks 0x%08x)", card->quirks); + else + quirk_str[0] = '\0'; + pr_info("%s: %s %s %s%s%s\n", md->disk->disk_name, mmc_card_id(card), mmc_card_name(card), - cap_str, md->read_only ? "(ro)" : ""); + cap_str, md->read_only ? " (ro)" : "", quirk_str); if (mmc_blk_alloc_parts(card, md)) goto out; diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 2553d903a82b..59a4044ea4c2 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -2409,7 +2409,8 @@ EXPORT_SYMBOL(mmc_erase); int mmc_can_erase(struct mmc_card *card) { if ((card->host->caps & MMC_CAP_ERASE) && - (card->csd.cmdclass & CCC_ERASE) && card->erase_size) + (card->csd.cmdclass & CCC_ERASE) && card->erase_size && + !(card->quirks & MMC_QUIRK_ERASE_BROKEN)) return 1; return 0; } diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 73fad83acbcb..e7c9d3098ac0 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h @@ -283,6 +283,9 @@ struct mmc_card { #define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */ +#define MMC_QUIRK_ERASE_BROKEN (1<<31) /* Skip erase */ + + unsigned int erase_size; /* erase size in sectors */ unsigned int erase_shift; /* if erase unit is power 2 */ unsigned int pref_erase; /* in sectors */