diff options
author | Andrei Warkentin <andreiw@motorola.com> | 2011-04-12 16:06:53 -0400 |
---|---|---|
committer | Chris Ball <cjb@laptop.org> | 2011-05-24 21:01:34 -0400 |
commit | 6a7a6b45f454686a1549729bfbae31f0b3b595d6 (patch) | |
tree | dafdeae86c51d07c0115065114906d438781a50d | |
parent | f6a03cbf43e586211f8ea088148c8ecd3fc4b5be (diff) |
mmc: quirks: Fix erase/trim for certain SanDisk cards.
CMD38 argument is passed through EXT_CSD[113].
Signed-off-by: Andrei Warkentin <andreiw@motorola.com>
Signed-off-by: Chris Ball <cjb@laptop.org>
-rw-r--r-- | drivers/mmc/card/block.c | 43 | ||||
-rw-r--r-- | include/linux/mmc/card.h | 1 |
2 files changed, 43 insertions, 1 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index 288d27394ef9..c20995323348 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c | |||
@@ -48,6 +48,13 @@ MODULE_ALIAS("mmc:block"); | |||
48 | #endif | 48 | #endif |
49 | #define MODULE_PARAM_PREFIX "mmcblk." | 49 | #define MODULE_PARAM_PREFIX "mmcblk." |
50 | 50 | ||
51 | #define INAND_CMD38_ARG_EXT_CSD 113 | ||
52 | #define INAND_CMD38_ARG_ERASE 0x00 | ||
53 | #define INAND_CMD38_ARG_TRIM 0x01 | ||
54 | #define INAND_CMD38_ARG_SECERASE 0x80 | ||
55 | #define INAND_CMD38_ARG_SECTRIM1 0x81 | ||
56 | #define INAND_CMD38_ARG_SECTRIM2 0x88 | ||
57 | |||
51 | #define REL_WRITES_SUPPORTED(card) (mmc_card_mmc((card)) && \ | 58 | #define REL_WRITES_SUPPORTED(card) (mmc_card_mmc((card)) && \ |
52 | (((card)->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) || \ | 59 | (((card)->ext_csd.rel_param & EXT_CSD_WR_REL_PARAM_EN) || \ |
53 | ((card)->ext_csd.rel_sectors))) | 60 | ((card)->ext_csd.rel_sectors))) |
@@ -356,6 +363,16 @@ static int mmc_blk_issue_discard_rq(struct mmc_queue *mq, struct request *req) | |||
356 | else | 363 | else |
357 | arg = MMC_ERASE_ARG; | 364 | arg = MMC_ERASE_ARG; |
358 | 365 | ||
366 | if (card->quirks & MMC_QUIRK_INAND_CMD38) { | ||
367 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||
368 | INAND_CMD38_ARG_EXT_CSD, | ||
369 | arg == MMC_TRIM_ARG ? | ||
370 | INAND_CMD38_ARG_TRIM : | ||
371 | INAND_CMD38_ARG_ERASE, | ||
372 | 0); | ||
373 | if (err) | ||
374 | goto out; | ||
375 | } | ||
359 | err = mmc_erase(card, from, nr, arg); | 376 | err = mmc_erase(card, from, nr, arg); |
360 | out: | 377 | out: |
361 | spin_lock_irq(&md->lock); | 378 | spin_lock_irq(&md->lock); |
@@ -386,9 +403,28 @@ static int mmc_blk_issue_secdiscard_rq(struct mmc_queue *mq, | |||
386 | else | 403 | else |
387 | arg = MMC_SECURE_ERASE_ARG; | 404 | arg = MMC_SECURE_ERASE_ARG; |
388 | 405 | ||
406 | if (card->quirks & MMC_QUIRK_INAND_CMD38) { | ||
407 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||
408 | INAND_CMD38_ARG_EXT_CSD, | ||
409 | arg == MMC_SECURE_TRIM1_ARG ? | ||
410 | INAND_CMD38_ARG_SECTRIM1 : | ||
411 | INAND_CMD38_ARG_SECERASE, | ||
412 | 0); | ||
413 | if (err) | ||
414 | goto out; | ||
415 | } | ||
389 | err = mmc_erase(card, from, nr, arg); | 416 | err = mmc_erase(card, from, nr, arg); |
390 | if (!err && arg == MMC_SECURE_TRIM1_ARG) | 417 | if (!err && arg == MMC_SECURE_TRIM1_ARG) { |
418 | if (card->quirks & MMC_QUIRK_INAND_CMD38) { | ||
419 | err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, | ||
420 | INAND_CMD38_ARG_EXT_CSD, | ||
421 | INAND_CMD38_ARG_SECTRIM2, | ||
422 | 0); | ||
423 | if (err) | ||
424 | goto out; | ||
425 | } | ||
391 | err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG); | 426 | err = mmc_erase(card, from, nr, MMC_SECURE_TRIM2_ARG); |
427 | } | ||
392 | out: | 428 | out: |
393 | spin_lock_irq(&md->lock); | 429 | spin_lock_irq(&md->lock); |
394 | __blk_end_request(req, err, blk_rq_bytes(req)); | 430 | __blk_end_request(req, err, blk_rq_bytes(req)); |
@@ -941,6 +977,11 @@ static int mmc_add_disk(struct mmc_blk_data *md) | |||
941 | 977 | ||
942 | static const struct mmc_fixup blk_fixups[] = | 978 | static const struct mmc_fixup blk_fixups[] = |
943 | { | 979 | { |
980 | MMC_FIXUP("SEM02G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), | ||
981 | MMC_FIXUP("SEM04G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), | ||
982 | MMC_FIXUP("SEM08G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), | ||
983 | MMC_FIXUP("SEM16G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), | ||
984 | MMC_FIXUP("SEM32G", 0x2, 0x100, add_quirk, MMC_QUIRK_INAND_CMD38), | ||
944 | END_FIXUP | 985 | END_FIXUP |
945 | }; | 986 | }; |
946 | 987 | ||
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h index 0c7a58b14343..72a98681ef47 100644 --- a/include/linux/mmc/card.h +++ b/include/linux/mmc/card.h | |||
@@ -133,6 +133,7 @@ struct mmc_card { | |||
133 | #define MMC_QUIRK_BROKEN_CLK_GATING (1<<3) /* clock gating the sdio bus will make card fail */ | 133 | #define MMC_QUIRK_BROKEN_CLK_GATING (1<<3) /* clock gating the sdio bus will make card fail */ |
134 | #define MMC_QUIRK_NONSTD_FUNC_IF (1<<4) /* SDIO card has nonstd function interfaces */ | 134 | #define MMC_QUIRK_NONSTD_FUNC_IF (1<<4) /* SDIO card has nonstd function interfaces */ |
135 | #define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */ | 135 | #define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */ |
136 | #define MMC_QUIRK_INAND_CMD38 (1<<6) /* iNAND devices have broken CMD38 */ | ||
136 | 137 | ||
137 | unsigned int erase_size; /* erase size in sectors */ | 138 | unsigned int erase_size; /* erase size in sectors */ |
138 | unsigned int erase_shift; /* if erase unit is power 2 */ | 139 | unsigned int erase_shift; /* if erase unit is power 2 */ |