diff options
author | Gilad Broner <gbroner@codeaurora.org> | 2015-09-29 16:57:21 +0300 |
---|---|---|
committer | Subhash Jadavani <subhashj@codeaurora.org> | 2016-05-31 15:27:30 -0700 |
commit | 17a072dd256d9a3246abf28e78e62a65c63f84f1 (patch) | |
tree | a559ff01369a334d73a7ecec8cfc30659ee81570 | |
parent | 64be1cd3e02145b3ab5918b4526081840cbff477 (diff) |
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>
-rw-r--r-- | drivers/mmc/card/queue.c | 4 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 66 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci-msm.h | 4 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 15 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 3 | ||||
-rw-r--r-- | include/linux/mmc/host.h | 1 |
6 files changed, 88 insertions, 5 deletions
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index d647a1a19575..efe2059d4fad 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -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 : ""); diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 382df8e0df39..8801b3afa6ac 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -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, diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h index 50db9363ef4e..01ad6d1593a2 100644 --- a/drivers/mmc/host/sdhci-msm.h +++ b/drivers/mmc/host/sdhci-msm.h @@ -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__ */ diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index aed0584379d1..5f139a5b9c87 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -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, diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 5468abe9698b..a4017e6f6c8c 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -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 diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h index 0759649084dd..367e122d1f2f 100644 --- a/include/linux/mmc/host.h +++ b/include/linux/mmc/host.h @@ -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. |