Skip to content

Commit

Permalink
mmc: core: Disable HPI for certain Hynix eMMC cards
Browse files Browse the repository at this point in the history
Certain Hynix eMMC 4.41 cards might get broken when HPI feature is used
and hence this patch disables the HPI feature for such buggy cards.

As some of the other features like BKOPs/Cache/Sanitize are dependent on
HPI feature, those features would also get disabled if HPI is disabled.

Signed-off-by: Pratibhasagar V <pratibha@codeaurora.org>
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
[gdavis: Forward port and cleanup]
Signed-off-by: George G. Davis <george_davis@mentor.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
  • Loading branch information
Pratibhasagar V authored and storulf committed Jul 25, 2016
1 parent 8b7be8f commit 5320226
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 14 deletions.
6 changes: 0 additions & 6 deletions drivers/mmc/card/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -2499,12 +2499,6 @@ static int mmc_add_disk(struct mmc_blk_data *md)
return ret;
}

#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

static const struct mmc_fixup blk_fixups[] =
{
MMC_FIXUP("SEM02G", CID_MANFID_SANDISK, 0x100, add_quirk,
Expand Down
23 changes: 20 additions & 3 deletions drivers/mmc/core/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,17 @@ static const unsigned int tacc_mant[] = {
35, 40, 45, 50, 55, 60, 70, 80,
};

static const struct mmc_fixup mmc_ext_csd_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_EXT_CSD_REV(CID_NAME_ANY, CID_MANFID_HYNIX,
0x014a, add_quirk, MMC_QUIRK_BROKEN_HPI, 5),

END_FIXUP
};

#define UNSTUFF_BITS(resp,start,size) \
({ \
const int __size = size; \
Expand Down Expand Up @@ -375,6 +386,9 @@ static int mmc_decode_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_ext_csd_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];
Expand Down Expand Up @@ -506,7 +520,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->cid.year += 16;

/* check whether the eMMC card supports BKOPS */
if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
if (!mmc_card_broken_hpi(card) &&
ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
card->ext_csd.bkops = 1;
card->ext_csd.man_bkops_en =
(ext_csd[EXT_CSD_BKOPS_EN] &
Expand All @@ -519,7 +534,8 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
}

/* check whether the eMMC card supports HPI */
if (!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
if (!mmc_card_broken_hpi(card) &&
!broken_hpi && (ext_csd[EXT_CSD_HPI_FEATURES] & 0x1)) {
card->ext_csd.hpi = 1;
if (ext_csd[EXT_CSD_HPI_FEATURES] & 0x2)
card->ext_csd.hpi_cmd = MMC_STOP_TRANSMISSION;
Expand Down Expand Up @@ -1675,7 +1691,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* If cache size is higher than 0, this indicates
* the existence of cache and it can be turned on.
*/
if (card->ext_csd.cache_size > 0) {
if (!mmc_card_broken_hpi(card) &&
card->ext_csd.cache_size > 0) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_CACHE_CTRL, 1,
card->ext_csd.generic_cmd6_time);
Expand Down
2 changes: 2 additions & 0 deletions drivers/mmc/core/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ void mmc_fixup_device(struct mmc_card *card, const struct mmc_fixup *table)
f->cis_vendor == (u16) SDIO_ANY_ID) &&
(f->cis_device == card->cis.device ||
f->cis_device == (u16) SDIO_ANY_ID) &&
(f->ext_csd_rev == EXT_CSD_REV_ANY ||
f->ext_csd_rev == card->ext_csd.rev) &&
rev >= f->rev_start && rev <= f->rev_end) {
dev_dbg(&card->dev, "calling %pf\n", f->vendor_fixup);
f->vendor_fixup(card, f->data);
Expand Down
35 changes: 30 additions & 5 deletions include/linux/mmc/card.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ struct mmc_card {
#define MMC_QUIRK_SEC_ERASE_TRIM_BROKEN (1<<10) /* Skip secure for erase/trim */
#define MMC_QUIRK_BROKEN_IRQ_POLLING (1<<11) /* Polling SDIO_CCCR_INTx could create a fake interrupt */
#define MMC_QUIRK_TRIM_BROKEN (1<<12) /* Skip trim */
#define MMC_QUIRK_BROKEN_HPI (1<<13) /* Disable broken HPI support */


unsigned int erase_size; /* erase size in sectors */
Expand Down Expand Up @@ -354,6 +355,9 @@ struct mmc_fixup {
/* SDIO-specfic fields. You can use SDIO_ANY_ID here of course */
u16 cis_vendor, cis_device;

/* for MMC cards */
unsigned int ext_csd_rev;

void (*vendor_fixup)(struct mmc_card *card, int data);
int data;
};
Expand All @@ -362,11 +366,20 @@ struct mmc_fixup {
#define CID_OEMID_ANY ((unsigned short) -1)
#define CID_NAME_ANY (NULL)

#define EXT_CSD_REV_ANY (-1u)

#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 END_FIXUP { NULL }

#define _FIXUP_EXT(_name, _manfid, _oemid, _rev_start, _rev_end, \
_cis_vendor, _cis_device, \
_fixup, _data) \
_fixup, _data, _ext_csd_rev) \
{ \
.name = (_name), \
.manfid = (_manfid), \
Expand All @@ -377,23 +390,30 @@ struct mmc_fixup {
.cis_device = (_cis_device), \
.vendor_fixup = (_fixup), \
.data = (_data), \
.ext_csd_rev = (_ext_csd_rev), \
}

#define MMC_FIXUP_REV(_name, _manfid, _oemid, _rev_start, _rev_end, \
_fixup, _data) \
_fixup, _data, _ext_csd_rev) \
_FIXUP_EXT(_name, _manfid, \
_oemid, _rev_start, _rev_end, \
SDIO_ANY_ID, SDIO_ANY_ID, \
_fixup, _data) \
_fixup, _data, _ext_csd_rev) \

#define MMC_FIXUP(_name, _manfid, _oemid, _fixup, _data) \
MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data)
MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \
EXT_CSD_REV_ANY)

#define MMC_FIXUP_EXT_CSD_REV(_name, _manfid, _oemid, _fixup, _data, \
_ext_csd_rev) \
MMC_FIXUP_REV(_name, _manfid, _oemid, 0, -1ull, _fixup, _data, \
_ext_csd_rev)

#define SDIO_FIXUP(_vendor, _device, _fixup, _data) \
_FIXUP_EXT(CID_NAME_ANY, CID_MANFID_ANY, \
CID_OEMID_ANY, 0, -1ull, \
_vendor, _device, \
_fixup, _data) \
_fixup, _data, EXT_CSD_REV_ANY) \

#define cid_rev(hwrev, fwrev, year, month) \
(((u64) hwrev) << 40 | \
Expand Down Expand Up @@ -512,6 +532,11 @@ static inline int mmc_card_broken_irq_polling(const struct mmc_card *c)
return c->quirks & MMC_QUIRK_BROKEN_IRQ_POLLING;
}

static inline int mmc_card_broken_hpi(const struct mmc_card *c)
{
return c->quirks & MMC_QUIRK_BROKEN_HPI;
}

#define mmc_card_name(c) ((c)->cid.prod_name)
#define mmc_card_id(c) (dev_name(&(c)->dev))

Expand Down

0 comments on commit 5320226

Please sign in to comment.