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>
This commit is contained in:
parent
d09bc854df
commit
dec9d9b888
|
@ -169,9 +169,35 @@ static inline void mmc_should_fail_request(struct mmc_host *host,
|
|||
|
||||
#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) {
|
||||
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));
|
||||
|
@ -334,8 +360,11 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
|||
* frequency will be done after current thread
|
||||
* releases host.
|
||||
*/
|
||||
mmc_clk_scaling(host, false);
|
||||
host->clk_scaling.start_busy = ktime_get();
|
||||
mmc_clk_scaling_update_state(host, mrq);
|
||||
if (!host->clk_scaling.invalid_state) {
|
||||
mmc_clk_scaling(host, false);
|
||||
host->clk_scaling.start_busy = ktime_get();
|
||||
}
|
||||
}
|
||||
|
||||
host->ops->request(host, mrq);
|
||||
|
@ -2984,7 +3013,8 @@ static bool mmc_is_vaild_state_for_clk_scaling(struct mmc_host *host)
|
|||
* this mode.
|
||||
*/
|
||||
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;
|
||||
|
||||
if (mmc_send_status(card, &status)) {
|
||||
|
|
|
@ -445,6 +445,8 @@ struct mmc_host {
|
|||
bool enable;
|
||||
bool initialized;
|
||||
bool in_progress;
|
||||
/* freq. transitions are not allowed in invalid state */
|
||||
bool invalid_state;
|
||||
struct delayed_work work;
|
||||
enum mmc_load state;
|
||||
} clk_scaling;
|
||||
|
|
Loading…
Reference in New Issue