Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions drivers/mmc/core/card.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,10 @@ struct mmc_fixup {
#define CID_MANFID_SAMSUNG 0x15
#define CID_MANFID_SAMSUNG_SD 0x1b
#define CID_MANFID_APACER 0x27
#define CID_MANFID_BIWIN_SD 0x4E
#define CID_MANFID_SWISSBIT 0x5D
#define CID_MANFID_KINGSTON 0x70
#define CID_MANFID_TRANSCEND_SD 0x74
#define CID_MANFID_HYNIX 0x90
#define CID_MANFID_KINGSTON_SD 0x9F
#define CID_MANFID_LONGSYS_SD 0xAD
Expand Down
3 changes: 3 additions & 0 deletions drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ static const unsigned freqs[] = { 400000, 300000, 200000, 100000 };
bool use_spi_crc = 1;
module_param(use_spi_crc, bool, 0);

uint max_posted_writes = 1;
module_param(max_posted_writes, uint, 0644);

static int mmc_schedule_delayed_work(struct delayed_work *work,
unsigned long delay)
{
Expand Down
1 change: 1 addition & 0 deletions drivers/mmc/core/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ int mmc_attach_sdio(struct mmc_host *host);

/* Module parameters */
extern bool use_spi_crc;
extern uint max_posted_writes;

/* Debugfs information for hosts and cards */
#ifdef CONFIG_DEBUG_FS
Expand Down
10 changes: 10 additions & 0 deletions drivers/mmc/core/quirks.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ static const struct mmc_fixup __maybe_unused mmc_sd_fixups[] = {
0, -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
MMC_QUIRK_BROKEN_SD_CACHE, EXT_CSD_REV_ANY),

/* Transcend cards need a CMD49 workaround */
_FIXUP_EXT("USDU1", CID_MANFID_TRANSCEND_SD, 0x4a60, CID_YEAR_ANY, CID_MONTH_ANY,
cid_rev(2, 0, 0, 0), -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
MMC_QUIRK_NONSTD_SD_CMD49, EXT_CSD_REV_ANY),

/* Certain Biwin cards need a CMD49 workaround */
_FIXUP_EXT("SMI ", CID_MANFID_BIWIN_SD, 0x4257, CID_YEAR_ANY, CID_MONTH_ANY,
cid_rev(1, 0, 2025, 0), -1ull, SDIO_ANY_ID, SDIO_ANY_ID, add_quirk_sd,
MMC_QUIRK_NONSTD_SD_CMD49, EXT_CSD_REV_ANY),

/* SD A2 allow-list - only trust CQ on these cards */
/* Raspberry Pi A2 cards */
_FIXUP_EXT(CID_NAME_ANY, CID_MANFID_LONGSYS_SD, 0x4c53, CID_YEAR_ANY, CID_MONTH_ANY,
Expand Down
22 changes: 21 additions & 1 deletion drivers/mmc/core/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1218,6 +1218,26 @@ static int mmc_sd_read_ext_regs(struct mmc_card *card)
goto out;
}

/* Some cards have zeroes in GEN_INFO but correctly implement EXT_PERF and EXT_PWR */
if (!memcmp(card->ext_reg_buf, gen_info_buf, 512)) {
pr_info("%s: using fall-back extension register parsing\n",
mmc_hostname(card->host));
/* PWR typically hard-coded at FNO=1 */
err = sd_parse_ext_reg_power(card, 1, 0, 0);
if (err) {
pr_err("%s: error %d parsing SD Power extension\n",
mmc_hostname(card->host), err);
goto out;
}
/* PERF typically hard-coded at FNO=2 */
err = sd_parse_ext_reg_perf(card, 2, 0, 0);
if (err) {
pr_err("%s: error %d parsing SD Performance extension\n",
mmc_hostname(card->host), err);
}
goto out;
}

/* General info structure revision. */
memcpy(&rev, &gen_info_buf[0], 2);

Expand Down Expand Up @@ -1387,7 +1407,7 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,

card->ocr = ocr;
card->type = MMC_TYPE_SD;
card->max_posted_writes = 1;
card->max_posted_writes = max_posted_writes;
memcpy(card->raw_cid, cid, sizeof(card->raw_cid));
}

Expand Down
19 changes: 16 additions & 3 deletions drivers/mmc/core/sd_ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,10 +421,23 @@ int mmc_sd_write_ext_reg(struct mmc_card *card, u8 fno, u8 page, u16 offset,
* [17:9] offset address.
* [8:0] length (0 = 1 byte).
*/
cmd.arg = fno << 27 | page << 18 | offset << 9;
if (card->quirks & MMC_QUIRK_NONSTD_SD_CMD49) {
int err;
/*
* Card ignores length/offset and always applies
* all 512B of the write data block. RmW cycle required.
*/
err = mmc_sd_read_ext_reg(card, fno, page, 0, 512, reg_buf);
if (err)
return err;

/* The first byte in the buffer is the data to be written. */
reg_buf[0] = reg_data;
cmd.arg = fno << 27 | page << 18;
reg_buf[offset] = reg_data;
} else {
cmd.arg = fno << 27 | page << 18 | offset << 9;
/* The first byte in the buffer is the data to be written. */
reg_buf[0] = reg_data;
}

data.flags = MMC_DATA_WRITE;
data.blksz = 512;
Expand Down
1 change: 1 addition & 0 deletions include/linux/mmc/card.h
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,7 @@ struct mmc_card {
#define MMC_QUIRK_BROKEN_CACHE_FLUSH (1<<16) /* Don't flush cache until the write has occurred */
#define MMC_QUIRK_BROKEN_SD_POWEROFF_NOTIFY (1<<17) /* Disable broken SD poweroff notify support */
#define MMC_QUIRK_NO_UHS_DDR50_TUNING (1<<18) /* Disable DDR50 tuning */
#define MMC_QUIRK_NONSTD_SD_CMD49 (1<<29) /* SD card ignores length/offset argument */
#define MMC_QUIRK_WORKING_SD_CQ (1<<30) /* SD card has known-good CQ implementation */
#define MMC_QUIRK_ERASE_BROKEN (1<<31) /* Skip erase */

Expand Down