diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c index 26ae35e9d023..188ace67504b 100644 --- a/drivers/mmc/core/core.c +++ b/drivers/mmc/core/core.c @@ -127,6 +127,41 @@ 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 && !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 * @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 ktime_t diff; #endif - if (host->card && host->clk_scaling.enable) - host->clk_scaling.busy_time_us += - ktime_to_us(ktime_sub(ktime_get(), - host->clk_scaling.start_busy)); + if (host->card) + mmc_update_clk_scaling(host); /* Flag re-tuning needed on CRC errors */ 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 * 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(); + } } __mmc_start_request(host, mrq); @@ -2811,7 +2847,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)) { diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 82cb8b901e8b..ff861fd2517b 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -450,6 +450,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;