summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdrivers/mmc/core/mmc.c19
-rw-r--r--drivers/mmc/core/mmc_ops.c6
-rw-r--r--include/linux/mmc/card.h9
3 files changed, 32 insertions, 2 deletions
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 9af23fe2ae8f..e450fbc66559 100755
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -58,6 +58,16 @@ static const unsigned int tacc_mant[] = {
__res & __mask; \
})
+static const struct mmc_fixup mmc_fixups[] = {
+ /*
+ * Certain Hynix eMMC 4.41 cards might get broken when HPI feature
+ * is used so disable the HPI feature for such buggy cards.
+ */
+ MMC_FIXUP(CID_NAME_ANY, CID_MANFID_HYNIX, 0x014a, add_quirk,
+ MMC_QUIRK_BROKEN_HPI),
+ END_FIXUP
+};
+
/*
* Given the decoded CSD structure, decode the raw CID to our CID structure.
*/
@@ -271,6 +281,9 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
*/
card->ext_csd.rev = ext_csd[EXT_CSD_REV];
+ /* fixup device after ext_csd revision field is updated */
+ mmc_fixup_device(card, mmc_fixups);
+
card->ext_csd.raw_sectors[0] = ext_csd[EXT_CSD_SEC_CNT + 0];
card->ext_csd.raw_sectors[1] = ext_csd[EXT_CSD_SEC_CNT + 1];
card->ext_csd.raw_sectors[2] = ext_csd[EXT_CSD_SEC_CNT + 2];
@@ -414,7 +427,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
if (card->ext_csd.rev >= 5) {
card->ext_csd.rel_param = ext_csd[EXT_CSD_WR_REL_PARAM];
/* check whether the eMMC card supports HPI */
- if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) {
+ if ((ext_csd[EXT_CSD_HPI_FEATURES] & 0x1) &&
+ !(card->quirks & MMC_QUIRK_BROKEN_HPI)) {
card->ext_csd.hpi = 1;
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
@@ -429,7 +443,8 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}
/* Check whether the eMMC card supports background ops */
- if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1)
+ if ((ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) &&
+ card->ext_csd.hpi)
card->ext_csd.bk_ops = 1;
/* Check whether the eMMC card needs proactive refresh */
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index c85c58aca3e2..b9b472796a64 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -555,6 +555,12 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
unsigned int flags;
int err;
+ if (!card->ext_csd.hpi_en) {
+ pr_warning("%s: Card didn't support HPI command\n",
+ mmc_hostname(card->host));
+ return -EINVAL;
+ }
+
opcode = card->ext_csd.hpi_cmd;
flags = MMC_RSP_R1 | MMC_CMD_AC;
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index ff194e553634..9eb6c6babd13 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -208,6 +208,8 @@ struct mmc_card {
#define MMC_QUIRK_DISABLE_CD (1<<5) /* disconnect CD/DAT[3] resistor */
#define MMC_QUIRK_INAND_CMD38 (1<<6) /* iNAND devices have broken CMD38 */
#define MMC_QUIRK_BLK_NO_CMD23 (1<<7) /* Avoid CMD23 for regular multiblock */
+#define MMC_QUIRK_BROKEN_HPI (1<<8) /* To avoid eMMC device getting broken permanently */
+ /* due to HPI feature */
unsigned int erase_size; /* erase size in sectors */
unsigned int erase_shift; /* if erase unit is power 2 */
@@ -264,6 +266,13 @@ struct mmc_fixup {
int data;
};
+#define CID_MANFID_SANDISK 0x2
+#define CID_MANFID_TOSHIBA 0x11
+#define CID_MANFID_MICRON 0x13
+#define CID_MANFID_SAMSUNG 0x15
+#define CID_MANFID_KINGSTON 0x70
+#define CID_MANFID_HYNIX 0x90
+
#define CID_MANFID_ANY (-1u)
#define CID_OEMID_ANY ((unsigned short) -1)
#define CID_NAME_ANY (NULL)