mmc: core: extend SDR104 workaround for other paths
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, commit <aafc430b36f3> ("mmc: sd: reduce the bus speed in case of multiple CRC errors") would reinit the card to lower speed (SDR50) hoping that CRC error rate would reduce at lower clock speed (100MHz for SDR50). As the error may happen for any cmd, this change tries to fix several other paths - clock scaling, mmc_rescan, non-data commands error path. Change-Id: I8ccbbf7e330cde3862d9660d3be4d67fb00d97ca Signed-off-by: Sahitya Tummala <stummala@codeaurora.org> Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org> Signed-off-by: Veerabhadrarao Badiganti <vbadigan@codeaurora.org>
This commit is contained in:
parent
60be71604a
commit
b8189b1707
3 changed files with 53 additions and 11 deletions
|
@ -1707,6 +1707,8 @@ static int mmc_blk_cmd_recovery(struct mmc_card *card, struct request *req,
|
|||
|
||||
/* We couldn't get a response from the card. Give up. */
|
||||
if (err) {
|
||||
if (card->err_in_sdr104)
|
||||
return ERR_RETRY;
|
||||
/* Check if the card is removed */
|
||||
if (mmc_detect_card_removed(card->host))
|
||||
return ERR_NOMEDIUM;
|
||||
|
@ -2197,7 +2199,8 @@ static int mmc_blk_err_check(struct mmc_card *card,
|
|||
brq->data.error == -ETIMEDOUT ||
|
||||
brq->cmd.error == -EILSEQ ||
|
||||
brq->cmd.error == -EIO ||
|
||||
brq->cmd.error == -ETIMEDOUT))
|
||||
brq->cmd.error == -ETIMEDOUT ||
|
||||
brq->sbc.error))
|
||||
card->err_in_sdr104 = true;
|
||||
|
||||
/*
|
||||
|
|
|
@ -464,6 +464,22 @@ out:
|
|||
}
|
||||
EXPORT_SYMBOL(mmc_clk_update_freq);
|
||||
|
||||
void mmc_recovery_fallback_lower_speed(struct mmc_host *host)
|
||||
{
|
||||
if (!host->card)
|
||||
return;
|
||||
|
||||
if (host->sdr104_wa && mmc_card_sd(host->card) &&
|
||||
(host->ios.timing == MMC_TIMING_UHS_SDR104) &&
|
||||
!host->card->sdr104_blocked) {
|
||||
pr_err("%s: %s: blocked SDR104, lower the bus-speed (SDR50 / DDR50)\n",
|
||||
mmc_hostname(host), __func__);
|
||||
mmc_host_clear_sdr104(host);
|
||||
mmc_hw_reset(host);
|
||||
host->card->sdr104_blocked = true;
|
||||
}
|
||||
}
|
||||
|
||||
static int mmc_devfreq_set_target(struct device *dev,
|
||||
unsigned long *freq, u32 devfreq_flags)
|
||||
{
|
||||
|
@ -510,6 +526,9 @@ static int mmc_devfreq_set_target(struct device *dev,
|
|||
if (abort)
|
||||
goto out;
|
||||
|
||||
if (mmc_card_sd(host->card) && host->card->sdr104_blocked)
|
||||
goto rel_host;
|
||||
|
||||
/*
|
||||
* In case we were able to claim host there is no need to
|
||||
* defer the frequency change. It will be done now
|
||||
|
@ -518,15 +537,18 @@ static int mmc_devfreq_set_target(struct device *dev,
|
|||
|
||||
mmc_host_clk_hold(host);
|
||||
err = mmc_clk_update_freq(host, *freq, clk_scaling->state);
|
||||
if (err && err != -EAGAIN)
|
||||
if (err && err != -EAGAIN) {
|
||||
pr_err("%s: clock scale to %lu failed with error %d\n",
|
||||
mmc_hostname(host), *freq, err);
|
||||
else
|
||||
mmc_recovery_fallback_lower_speed(host);
|
||||
} else {
|
||||
pr_debug("%s: clock change to %lu finished successfully (%s)\n",
|
||||
mmc_hostname(host), *freq, current->comm);
|
||||
}
|
||||
|
||||
|
||||
mmc_host_clk_release(host);
|
||||
rel_host:
|
||||
mmc_release_host(host);
|
||||
out:
|
||||
return err;
|
||||
|
@ -547,6 +569,9 @@ void mmc_deferred_scaling(struct mmc_host *host)
|
|||
if (!host->clk_scaling.enable)
|
||||
return;
|
||||
|
||||
if (mmc_card_sd(host->card) && host->card->sdr104_blocked)
|
||||
return;
|
||||
|
||||
spin_lock_bh(&host->clk_scaling.lock);
|
||||
|
||||
if (host->clk_scaling.clk_scaling_in_progress ||
|
||||
|
@ -567,13 +592,15 @@ void mmc_deferred_scaling(struct mmc_host *host)
|
|||
|
||||
err = mmc_clk_update_freq(host, target_freq,
|
||||
host->clk_scaling.state);
|
||||
if (err && err != -EAGAIN)
|
||||
if (err && err != -EAGAIN) {
|
||||
pr_err("%s: failed on deferred scale clocks (%d)\n",
|
||||
mmc_hostname(host), err);
|
||||
else
|
||||
mmc_recovery_fallback_lower_speed(host);
|
||||
} else {
|
||||
pr_debug("%s: clocks were successfully scaled to %lu (%s)\n",
|
||||
mmc_hostname(host),
|
||||
target_freq, current->comm);
|
||||
}
|
||||
host->clk_scaling.clk_scaling_in_progress = false;
|
||||
atomic_dec(&host->clk_scaling.devfreq_abort);
|
||||
}
|
||||
|
@ -1469,8 +1496,13 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
|
|||
}
|
||||
}
|
||||
if (!cmd->error || !cmd->retries ||
|
||||
mmc_card_removed(host->card))
|
||||
mmc_card_removed(host->card)) {
|
||||
if (cmd->error && !cmd->retries &&
|
||||
cmd->opcode != MMC_SEND_STATUS &&
|
||||
cmd->opcode != MMC_SEND_TUNING_BLOCK)
|
||||
mmc_recovery_fallback_lower_speed(host);
|
||||
break;
|
||||
}
|
||||
|
||||
mmc_retune_recheck(host);
|
||||
|
||||
|
@ -4038,12 +4070,18 @@ 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;
|
||||
if (host->ops->get_cd && host->ops->get_cd(host)) {
|
||||
mmc_recovery_fallback_lower_speed(host);
|
||||
ret = 0;
|
||||
} else {
|
||||
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));
|
||||
}
|
||||
pr_debug("%s: card remove detected\n", mmc_hostname(host));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
|
|
@ -223,6 +223,7 @@ extern void mmc_cmdq_clk_scaling_start_busy(struct mmc_host *host,
|
|||
bool lock_needed);
|
||||
extern void mmc_cmdq_clk_scaling_stop_busy(struct mmc_host *host,
|
||||
bool lock_needed, bool is_cmdq_dcmd);
|
||||
extern void mmc_recovery_fallback_lower_speed(struct mmc_host *host);
|
||||
|
||||
/**
|
||||
* mmc_claim_host - exclusively claim a host
|
||||
|
|
Loading…
Add table
Reference in a new issue