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:
Gilad Broner 2015-09-29 16:57:21 +03:00 committed by Subhash Jadavani
parent 64be1cd3e0
commit 17a072dd25
6 changed files with 88 additions and 5 deletions

View file

@ -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 : "");

View file

@ -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,

View file

@ -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__ */

View file

@ -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,

View file

@ -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

View file

@ -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.