mirror of https://github.com/hak5/openwrt.git
133 lines
4.3 KiB
Diff
133 lines
4.3 KiB
Diff
|
From 6d11059a087b8101cf34a09a1e3342bb4f1576de Mon Sep 17 00:00:00 2001
|
||
|
From: Phil Elwell <phil@raspberrypi.org>
|
||
|
Date: Wed, 11 May 2016 12:50:33 +0100
|
||
|
Subject: [PATCH] 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 <phil@raspberrypi.org>
|
||
|
|
||
|
mmc: Apply QUIRK_BROKEN_ERASE to other capacities
|
||
|
|
||
|
Signed-off-by: Phil Elwell <phil@raspberrypi.org>
|
||
|
|
||
|
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 <phil@raspberrypi.org>
|
||
|
---
|
||
|
drivers/mmc/card/block.c | 39 ++++++++++++++++++++++++++++++++++++---
|
||
|
drivers/mmc/core/core.c | 3 ++-
|
||
|
include/linux/mmc/card.h | 3 +++
|
||
|
3 files changed, 41 insertions(+), 4 deletions(-)
|
||
|
|
||
|
--- 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
|
||
|
{
|
||
|
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
|
||
|
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
|
||
|
|
||
|
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;
|
||
|
--- 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;
|
||
|
}
|
||
|
--- 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 */
|