mmc: core: Fix clock frequency transitions during invalid states
eMMC and SD card specifications restrict the usage of a class of commands while commands in other class are in progress. For example, during erase operations the SD/eMMC spec. allows only CMD35, CMD36, CMD38. If clock scaling is enabled and decide to scale up the clocks it may be possible that CMD19/21 tuning commands are sent in between erase commands, which is illegal as per specification. Fix such illegal transactions to the card and also make clock scaling statistics accountable only for read/write commands instead of time consuming commands, like CMD38 erase, where transactions are independent of bus frequency. Change-Id: Iffba175787837e7f95bde8970f19d0f0f9d7d67d Signed-off-by: Sujit Reddy Thumma <sthumma@codeaurora.org> [merez@codeaurora.org: fix conflicts as mmc_update_clk_scaling is missing on 3.14] Signed-off-by: Maya Erez <merez@codeaurora.org>
This commit is contained in:
parent
90102c17f9
commit
3332d5a9e4
2 changed files with 46 additions and 7 deletions
|
@ -127,6 +127,41 @@ static inline void mmc_should_fail_request(struct mmc_host *host,
|
||||||
|
|
||||||
#endif /* CONFIG_FAIL_MMC_REQUEST */
|
#endif /* CONFIG_FAIL_MMC_REQUEST */
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
mmc_clk_scaling_update_state(struct mmc_host *host, struct mmc_request *mrq)
|
||||||
|
{
|
||||||
|
if (mrq) {
|
||||||
|
switch (mrq->cmd->opcode) {
|
||||||
|
case MMC_READ_SINGLE_BLOCK:
|
||||||
|
case MMC_READ_MULTIPLE_BLOCK:
|
||||||
|
case MMC_WRITE_BLOCK:
|
||||||
|
case MMC_WRITE_MULTIPLE_BLOCK:
|
||||||
|
host->clk_scaling.invalid_state = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
host->clk_scaling.invalid_state = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* force clock scaling transitions,
|
||||||
|
* if other conditions are met
|
||||||
|
*/
|
||||||
|
host->clk_scaling.invalid_state = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mmc_update_clk_scaling(struct mmc_host *host)
|
||||||
|
{
|
||||||
|
if (host->clk_scaling.enable && !host->clk_scaling.invalid_state) {
|
||||||
|
host->clk_scaling.busy_time_us +=
|
||||||
|
ktime_to_us(ktime_sub(ktime_get(),
|
||||||
|
host->clk_scaling.start_busy));
|
||||||
|
host->clk_scaling.start_busy = ktime_get();
|
||||||
|
}
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* mmc_request_done - finish processing an MMC request
|
* mmc_request_done - finish processing an MMC request
|
||||||
* @host: MMC host which completed request
|
* @host: MMC host which completed request
|
||||||
|
@ -142,10 +177,8 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
|
||||||
#ifdef CONFIG_MMC_PERF_PROFILING
|
#ifdef CONFIG_MMC_PERF_PROFILING
|
||||||
ktime_t diff;
|
ktime_t diff;
|
||||||
#endif
|
#endif
|
||||||
if (host->card && host->clk_scaling.enable)
|
if (host->card)
|
||||||
host->clk_scaling.busy_time_us +=
|
mmc_update_clk_scaling(host);
|
||||||
ktime_to_us(ktime_sub(ktime_get(),
|
|
||||||
host->clk_scaling.start_busy));
|
|
||||||
|
|
||||||
/* Flag re-tuning needed on CRC errors */
|
/* Flag re-tuning needed on CRC errors */
|
||||||
if ((cmd->opcode != MMC_SEND_TUNING_BLOCK &&
|
if ((cmd->opcode != MMC_SEND_TUNING_BLOCK &&
|
||||||
|
@ -340,8 +373,11 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||||
* frequency will be done after current thread
|
* frequency will be done after current thread
|
||||||
* releases host.
|
* releases host.
|
||||||
*/
|
*/
|
||||||
mmc_clk_scaling(host, false);
|
mmc_clk_scaling_update_state(host, mrq);
|
||||||
host->clk_scaling.start_busy = ktime_get();
|
if (!host->clk_scaling.invalid_state) {
|
||||||
|
mmc_clk_scaling(host, false);
|
||||||
|
host->clk_scaling.start_busy = ktime_get();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
__mmc_start_request(host, mrq);
|
__mmc_start_request(host, mrq);
|
||||||
|
@ -2811,7 +2847,8 @@ static bool mmc_is_vaild_state_for_clk_scaling(struct mmc_host *host)
|
||||||
* this mode.
|
* this mode.
|
||||||
*/
|
*/
|
||||||
if (!card || (mmc_card_mmc(card) &&
|
if (!card || (mmc_card_mmc(card) &&
|
||||||
card->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB))
|
card->part_curr == EXT_CSD_PART_CONFIG_ACC_RPMB)
|
||||||
|
|| host->clk_scaling.invalid_state)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (mmc_send_status(card, &status)) {
|
if (mmc_send_status(card, &status)) {
|
||||||
|
|
|
@ -450,6 +450,8 @@ struct mmc_host {
|
||||||
bool enable;
|
bool enable;
|
||||||
bool initialized;
|
bool initialized;
|
||||||
bool in_progress;
|
bool in_progress;
|
||||||
|
/* freq. transitions are not allowed in invalid state */
|
||||||
|
bool invalid_state;
|
||||||
struct delayed_work work;
|
struct delayed_work work;
|
||||||
enum mmc_load state;
|
enum mmc_load state;
|
||||||
} clk_scaling;
|
} clk_scaling;
|
||||||
|
|
Loading…
Add table
Reference in a new issue