mmc: sd: reduce the bus speed in case of multiple CRC errors in SDR104
UHS-I SD cards support SDR104 mode which runs the SD card interface clock upto 208 MHz. But we may see repeated CRC errors in SDR104 with some SDCC controllers. If this happens, this change would reinit the card to lower speed (SDR50) hoping that CRC error rate would reduce at lower clock speed (100MHz for SDR50). Change-Id: I140d29fdf500bb89881a0f2c1f768fe0c5afa9d5 Signed-off-by: Asutosh Das <asutoshd@codeaurora.org> Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
parent
a4b36d773b
commit
0cbf1d2db7
7 changed files with 76 additions and 2 deletions
|
@ -2189,6 +2189,17 @@ static int mmc_blk_err_check(struct mmc_card *card,
|
|||
int need_retune = card->host->need_retune;
|
||||
int ecc_err = 0, gen_err = 0;
|
||||
|
||||
if (card->host->sdr104_wa && mmc_card_sd(card) &&
|
||||
(card->host->ios.timing == MMC_TIMING_UHS_SDR104) &&
|
||||
!card->sdr104_blocked &&
|
||||
(brq->data.error == -EILSEQ ||
|
||||
brq->data.error == -EIO ||
|
||||
brq->data.error == -ETIMEDOUT ||
|
||||
brq->cmd.error == -EILSEQ ||
|
||||
brq->cmd.error == -EIO ||
|
||||
brq->cmd.error == -ETIMEDOUT))
|
||||
card->err_in_sdr104 = true;
|
||||
|
||||
/*
|
||||
* sbc.error indicates a problem with the set block count
|
||||
* command. No data will have been transferred.
|
||||
|
@ -3645,6 +3656,7 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
|
|||
struct mmc_async_req *areq;
|
||||
const u8 packed_nr = 2;
|
||||
u8 reqs = 0;
|
||||
bool reset = false;
|
||||
#ifdef CONFIG_MMC_SIMULATE_MAX_SPEED
|
||||
unsigned long waitfor = jiffies;
|
||||
#endif
|
||||
|
@ -3690,6 +3702,26 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
|
|||
type = rq_data_dir(req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
|
||||
mmc_queue_bounce_post(mq_rq);
|
||||
|
||||
if (card->err_in_sdr104) {
|
||||
/*
|
||||
* Data CRC/timeout errors will manifest as CMD/DATA
|
||||
* ERR. But we'd like to retry these too.
|
||||
* Moreover, no harm done if this fails too for multiple
|
||||
* times, we anyway reduce the bus-speed and retry the
|
||||
* same request.
|
||||
* If that fails too, we don't override this status.
|
||||
*/
|
||||
if (status == MMC_BLK_ABORT ||
|
||||
status == MMC_BLK_CMD_ERR ||
|
||||
status == MMC_BLK_DATA_ERR ||
|
||||
status == MMC_BLK_RETRY)
|
||||
/* reset on all of these errors and retry */
|
||||
reset = true;
|
||||
|
||||
status = MMC_BLK_RETRY;
|
||||
card->err_in_sdr104 = false;
|
||||
}
|
||||
|
||||
switch (status) {
|
||||
case MMC_BLK_SUCCESS:
|
||||
case MMC_BLK_PARTIAL:
|
||||
|
@ -3730,8 +3762,32 @@ static int mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *rqc)
|
|||
break;
|
||||
case MMC_BLK_RETRY:
|
||||
retune_retry_done = brq->retune_retry_done;
|
||||
if (retry++ < MMC_BLK_MAX_RETRIES)
|
||||
if (retry++ < MMC_BLK_MAX_RETRIES) {
|
||||
break;
|
||||
} else if (reset) {
|
||||
reset = false;
|
||||
/*
|
||||
* If we exhaust all the retries due to
|
||||
* CRC/timeout errors in SDR140 mode with UHS SD
|
||||
* cards, re-configure the card in SDR50
|
||||
* bus-speed mode.
|
||||
* All subsequent re-init of this card will be
|
||||
* in SDR50 mode, unless it is removed and
|
||||
* re-inserted. When new UHS SD cards are
|
||||
* inserted, it may start at SDR104 mode if
|
||||
* supported by the card.
|
||||
*/
|
||||
pr_err("%s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n",
|
||||
req->rq_disk->disk_name);
|
||||
mmc_host_clear_sdr104(card->host);
|
||||
mmc_suspend_clk_scaling(card->host);
|
||||
mmc_blk_reset(md, card->host, type);
|
||||
/* SDR104 mode is blocked from now on */
|
||||
card->sdr104_blocked = true;
|
||||
/* retry 5 times again */
|
||||
retry = 0;
|
||||
break;
|
||||
}
|
||||
/* Fall through */
|
||||
case MMC_BLK_ABORT:
|
||||
if (!mmc_blk_reset(md, card->host, type) &&
|
||||
|
|
|
@ -4033,6 +4033,10 @@ int _mmc_detect_card_removed(struct mmc_host *host)
|
|||
|
||||
if (ret) {
|
||||
mmc_card_set_removed(host->card);
|
||||
if (host->card->sdr104_blocked) {
|
||||
mmc_host_set_sdr104(host);
|
||||
host->card->sdr104_blocked = false;
|
||||
}
|
||||
pr_debug("%s: card remove detected\n", mmc_hostname(host));
|
||||
}
|
||||
|
||||
|
|
|
@ -80,7 +80,6 @@ void mmc_init_context_info(struct mmc_host *host);
|
|||
|
||||
extern bool mmc_can_scale_clk(struct mmc_host *host);
|
||||
extern int mmc_init_clk_scaling(struct mmc_host *host);
|
||||
extern int mmc_suspend_clk_scaling(struct mmc_host *host);
|
||||
extern int mmc_resume_clk_scaling(struct mmc_host *host);
|
||||
extern int mmc_exit_clk_scaling(struct mmc_host *host);
|
||||
extern unsigned long mmc_get_max_frequency(struct mmc_host *host);
|
||||
|
|
|
@ -1285,6 +1285,8 @@ static int _mmc_sd_resume(struct mmc_host *host)
|
|||
#endif
|
||||
mmc_card_clr_suspended(host->card);
|
||||
|
||||
if (host->card->sdr104_blocked)
|
||||
goto out;
|
||||
err = mmc_resume_clk_scaling(host);
|
||||
if (err) {
|
||||
pr_err("%s: %s: fail to resume clock scaling (%d)\n",
|
||||
|
|
|
@ -435,6 +435,8 @@ struct mmc_card {
|
|||
u8 *cached_ext_csd;
|
||||
bool cmdq_init;
|
||||
struct mmc_bkops_info bkops;
|
||||
bool err_in_sdr104;
|
||||
bool sdr104_blocked;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
@ -169,6 +169,7 @@ extern int __mmc_switch_cmdq_mode(struct mmc_command *cmd, u8 set, u8 index,
|
|||
extern int mmc_send_tuning(struct mmc_host *host, u32 opcode, int *cmd_error);
|
||||
extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
|
||||
extern int mmc_set_auto_bkops(struct mmc_card *card, bool enable);
|
||||
extern int mmc_suspend_clk_scaling(struct mmc_host *host);
|
||||
|
||||
#define MMC_ERASE_ARG 0x00000000
|
||||
#define MMC_SECURE_ERASE_ARG 0x80000000
|
||||
|
|
|
@ -729,6 +729,16 @@ static inline int mmc_host_uhs(struct mmc_host *host)
|
|||
MMC_CAP_UHS_DDR50);
|
||||
}
|
||||
|
||||
static inline void mmc_host_clear_sdr104(struct mmc_host *host)
|
||||
{
|
||||
host->caps &= ~MMC_CAP_UHS_SDR104;
|
||||
}
|
||||
|
||||
static inline void mmc_host_set_sdr104(struct mmc_host *host)
|
||||
{
|
||||
host->caps |= MMC_CAP_UHS_SDR104;
|
||||
}
|
||||
|
||||
static inline int mmc_host_packed_wr(struct mmc_host *host)
|
||||
{
|
||||
return host->caps2 & MMC_CAP2_PACKED_WR;
|
||||
|
|
Loading…
Add table
Reference in a new issue