Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8cd402a5 authored by Sahitya Tummala's avatar Sahitya Tummala Committed by Subhash Jadavani
Browse files

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: default avatarSahitya Tummala <stummala@codeaurora.org>
Signed-off-by: default avatarSubhash Jadavani <subhashj@codeaurora.org>
Signed-off-by: default avatarVeerabhadrarao Badiganti <vbadigan@codeaurora.org>
parent 3ae97c70
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -1718,6 +1718,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;
@@ -2208,7 +2210,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;

	/*
+48 −10
Original line number Diff line number Diff line
@@ -456,6 +456,22 @@ int mmc_clk_update_freq(struct mmc_host *host,
}
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)
{
@@ -507,6 +523,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
@@ -515,15 +534,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;
@@ -544,6 +566,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 ||
@@ -564,13 +589,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);
}
@@ -1540,8 +1567,13 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
			}
		}
		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);

@@ -4196,12 +4228,18 @@ int _mmc_detect_card_removed(struct mmc_host *host)
	}

	if (ret) {
		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;
+1 −0
Original line number Diff line number Diff line
@@ -232,6 +232,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