mmc: sdhci-msm: add PM QoS legacy voting
Add PM QoS voting mechanism to sdhci-msm driver for legacy eMMC. Two types of voting schemes are supported: 1) Vote for HW IRQ 2) Vote for a cpu group according to the request's designated cpu Using PM QoS voting should benefit performance. Change-Id: I5d2b71fc4eabfa5060f343634fbc7363f2ee1344 Signed-off-by: Konstantin Dorfman <kdorfman@codeaurora.org> Signed-off-by: Gilad Broner <gbroner@codeaurora.org> [subhashj@codeaurora.org: fixed merge conflicts] Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
This commit is contained in:
parent
64be1cd3e0
commit
17a072dd25
6 changed files with 88 additions and 5 deletions
|
@ -479,6 +479,10 @@ cur_sg_alloc_failed:
|
|||
success:
|
||||
sema_init(&mq->thread_sem, 1);
|
||||
|
||||
/* hook for pm qos legacy init */
|
||||
if (card->host->ops->init)
|
||||
card->host->ops->init(card->host);
|
||||
|
||||
mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
|
||||
host->index, subname ? subname : "");
|
||||
|
||||
|
|
|
@ -3291,7 +3291,7 @@ static void sdhci_msm_pm_qos_cpu_unvote_work(struct work_struct *work)
|
|||
pm_qos_update_request(&group->req, group->latency);
|
||||
}
|
||||
|
||||
void sdhci_msm_pm_qos_cpu_unvote(struct sdhci_host *host, int cpu, bool async)
|
||||
bool sdhci_msm_pm_qos_cpu_unvote(struct sdhci_host *host, int cpu, bool async)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_msm_host *msm_host = pltfm_host->priv;
|
||||
|
@ -3299,16 +3299,17 @@ void sdhci_msm_pm_qos_cpu_unvote(struct sdhci_host *host, int cpu, bool async)
|
|||
|
||||
if (!msm_host->pm_qos_group_enable || group < 0 ||
|
||||
atomic_dec_return(&msm_host->pm_qos[group].counter))
|
||||
return;
|
||||
return false;
|
||||
|
||||
if (async) {
|
||||
schedule_work(&msm_host->pm_qos[group].unvote_work);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
msm_host->pm_qos[group].latency = PM_QOS_DEFAULT_VALUE;
|
||||
pm_qos_update_request(&msm_host->pm_qos[group].req,
|
||||
msm_host->pm_qos[group].latency);
|
||||
return true;
|
||||
}
|
||||
|
||||
void sdhci_msm_pm_qos_cpu_init(struct sdhci_host *host,
|
||||
|
@ -3346,9 +3347,65 @@ void sdhci_msm_pm_qos_cpu_init(struct sdhci_host *host,
|
|||
group->latency,
|
||||
&latency[i].latency[SDHCI_PERFORMANCE_MODE]);
|
||||
}
|
||||
msm_host->pm_qos_prev_cpu = -1;
|
||||
msm_host->pm_qos_group_enable = true;
|
||||
}
|
||||
|
||||
static void sdhci_msm_pre_req(struct sdhci_host *host,
|
||||
struct mmc_request *mmc_req)
|
||||
{
|
||||
int cpu;
|
||||
int group;
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_msm_host *msm_host = pltfm_host->priv;
|
||||
int prev_group = sdhci_msm_get_cpu_group(msm_host,
|
||||
msm_host->pm_qos_prev_cpu);
|
||||
|
||||
sdhci_msm_pm_qos_irq_vote(host);
|
||||
|
||||
cpu = get_cpu();
|
||||
put_cpu();
|
||||
group = sdhci_msm_get_cpu_group(msm_host, cpu);
|
||||
if (group < 0)
|
||||
return;
|
||||
|
||||
if (group != prev_group && prev_group >= 0) {
|
||||
sdhci_msm_pm_qos_cpu_unvote(host,
|
||||
msm_host->pm_qos_prev_cpu, false);
|
||||
prev_group = -1; /* make sure to vote for new group */
|
||||
}
|
||||
|
||||
if (prev_group < 0) {
|
||||
sdhci_msm_pm_qos_cpu_vote(host,
|
||||
msm_host->pdata->pm_qos_data.latency, cpu);
|
||||
msm_host->pm_qos_prev_cpu = cpu;
|
||||
}
|
||||
}
|
||||
|
||||
static void sdhci_msm_post_req(struct sdhci_host *host,
|
||||
struct mmc_request *mmc_req)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_msm_host *msm_host = pltfm_host->priv;
|
||||
|
||||
sdhci_msm_pm_qos_irq_unvote(host, false);
|
||||
|
||||
if (sdhci_msm_pm_qos_cpu_unvote(host, msm_host->pm_qos_prev_cpu, false))
|
||||
msm_host->pm_qos_prev_cpu = -1;
|
||||
}
|
||||
|
||||
static void sdhci_msm_init(struct sdhci_host *host)
|
||||
{
|
||||
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
|
||||
struct sdhci_msm_host *msm_host = pltfm_host->priv;
|
||||
|
||||
sdhci_msm_pm_qos_irq_init(host);
|
||||
|
||||
if (msm_host->pdata->pm_qos_data.legacy_valid)
|
||||
sdhci_msm_pm_qos_cpu_init(host,
|
||||
msm_host->pdata->pm_qos_data.latency);
|
||||
}
|
||||
|
||||
static struct sdhci_ops sdhci_msm_ops = {
|
||||
.crypto_engine_cfg = sdhci_msm_ice_cfg,
|
||||
.crypto_cfg_reset = sdhci_msm_ice_cfg_reset,
|
||||
|
@ -3372,6 +3429,9 @@ static struct sdhci_ops sdhci_msm_ops = {
|
|||
.detect = sdhci_msm_detect,
|
||||
.notify_load = sdhci_msm_notify_load,
|
||||
.reset_workaround = sdhci_msm_reset_workaround,
|
||||
.init = sdhci_msm_init,
|
||||
.pre_req = sdhci_msm_pre_req,
|
||||
.post_req = sdhci_msm_post_req,
|
||||
};
|
||||
|
||||
static void sdhci_set_default_hw_caps(struct sdhci_msm_host *msm_host,
|
||||
|
|
|
@ -203,7 +203,7 @@ struct sdhci_msm_host {
|
|||
struct sdhci_msm_ice_data ice;
|
||||
u32 ice_clk_rate;
|
||||
struct sdhci_msm_pm_qos_group *pm_qos;
|
||||
int pm_qos_prev_group;
|
||||
int pm_qos_prev_cpu;
|
||||
bool pm_qos_group_enable;
|
||||
struct sdhci_msm_pm_qos_irq pm_qos_irq;
|
||||
};
|
||||
|
@ -218,7 +218,7 @@ void sdhci_msm_pm_qos_cpu_init(struct sdhci_host *host,
|
|||
struct sdhci_msm_pm_qos_latency *latency);
|
||||
void sdhci_msm_pm_qos_cpu_vote(struct sdhci_host *host,
|
||||
struct sdhci_msm_pm_qos_latency *latency, int cpu);
|
||||
void sdhci_msm_pm_qos_cpu_unvote(struct sdhci_host *host, int cpu, bool async);
|
||||
bool sdhci_msm_pm_qos_cpu_unvote(struct sdhci_host *host, int cpu, bool async);
|
||||
|
||||
|
||||
#endif /* __SDHCI_MSM_H__ */
|
||||
|
|
|
@ -2512,6 +2512,8 @@ static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
|
|||
DMA_TO_DEVICE : DMA_FROM_DEVICE);
|
||||
data->host_cookie = COOKIE_UNMAPPED;
|
||||
}
|
||||
if (host->ops->post_req)
|
||||
host->ops->post_req(host, mrq);
|
||||
}
|
||||
|
||||
static int sdhci_pre_dma_transfer(struct sdhci_host *host,
|
||||
|
@ -2548,6 +2550,9 @@ static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
|
|||
|
||||
if (host->flags & SDHCI_REQ_USE_DMA)
|
||||
sdhci_pre_dma_transfer(host, mrq->data);
|
||||
|
||||
if (host->ops->pre_req)
|
||||
host->ops->pre_req(host, mrq);
|
||||
}
|
||||
|
||||
static void sdhci_card_event(struct mmc_host *mmc)
|
||||
|
@ -2589,7 +2594,17 @@ static void sdhci_detect(struct mmc_host *mmc, bool detected)
|
|||
host->ops->detect(host, detected);
|
||||
}
|
||||
|
||||
static int sdhci_late_init(struct mmc_host *mmc)
|
||||
{
|
||||
struct sdhci_host *host = mmc_priv(mmc);
|
||||
|
||||
if (host->ops->init)
|
||||
host->ops->init(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
static const struct mmc_host_ops sdhci_ops = {
|
||||
.init = sdhci_late_init,
|
||||
.request = sdhci_request,
|
||||
.post_req = sdhci_post_req,
|
||||
.pre_req = sdhci_pre_req,
|
||||
|
|
|
@ -680,6 +680,9 @@ struct sdhci_ops {
|
|||
int card_drv, int *drv_type);
|
||||
int (*notify_load)(struct sdhci_host *host, enum mmc_load state);
|
||||
void (*reset_workaround)(struct sdhci_host *host, u32 enable);
|
||||
void (*init)(struct sdhci_host *host);
|
||||
void (*pre_req)(struct sdhci_host *host, struct mmc_request *req);
|
||||
void (*post_req)(struct sdhci_host *host, struct mmc_request *req);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
|
||||
|
|
|
@ -103,6 +103,7 @@ struct mmc_cmdq_host_ops {
|
|||
};
|
||||
|
||||
struct mmc_host_ops {
|
||||
int (*init)(struct mmc_host *host);
|
||||
/*
|
||||
* 'enable' is called when the host is claimed and 'disable' is called
|
||||
* when the host is released. 'enable' and 'disable' are deprecated.
|
||||
|
|
Loading…
Add table
Reference in a new issue