mmc: sdhci-msm: add PM QoS voting
Add PM QoS voting mechanism to sdhci-msm driver for command queueing.
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: I8a20653eeb6348d5b442c846708d92c8fb64a8e9
Signed-off-by: Gilad Broner <gbroner@codeaurora.org>
[subhashj@codeaurora.org: fixed trivial merge conflicts]
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
[xiaonian@codeaurora.org: fixed trivial merge conflicts
and comiplation error]
Signed-off-by: Xiaonian Wang <xiaonian@codeaurora.org>
diff --git a/drivers/mmc/host/cmdq_hci.c b/drivers/mmc/host/cmdq_hci.c
index 8c8a8a7..0eb1ba0 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -24,8 +24,11 @@
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
#include <linux/pm_runtime.h>
+#include <linux/workqueue.h>
#include "cmdq_hci.h"
+#include "sdhci.h"
+#include "sdhci-msm.h"
#define DCMD_SLOT 31
#define NUM_SLOTS 32
@@ -575,6 +578,21 @@
}
+static void cmdq_pm_qos_vote(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ sdhci_msm_pm_qos_cpu_vote(host,
+ msm_host->pdata->pm_qos_data.cmdq_latency, mrq->req->cpu);
+}
+
+static void cmdq_pm_qos_unvote(struct sdhci_host *host, struct mmc_request *mrq)
+{
+ /* use async as we're inside an atomic context (soft-irq) */
+ sdhci_msm_pm_qos_cpu_unvote(host, mrq->req->cpu, true);
+}
+
static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
int err = 0;
@@ -582,6 +600,7 @@
u64 *task_desc = NULL;
u32 tag = mrq->cmdq_req->tag;
struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
+ struct sdhci_host *host = mmc_priv(mmc);
if (!cq_host->enabled) {
pr_err("%s: CMDQ host not enabled yet !!!\n",
@@ -619,6 +638,9 @@
if (cq_host->ops->set_tranfer_params)
cq_host->ops->set_tranfer_params(mmc);
+ /* PM QoS */
+ sdhci_msm_pm_qos_irq_vote(host);
+ cmdq_pm_qos_vote(host, mrq);
ring_doorbell:
/* Ensure the task descriptor list is flushed before ringing doorbell */
wmb();
@@ -770,6 +792,7 @@
int err)
{
struct mmc_data *data = mrq->data;
+ struct sdhci_host *sdhci_host = mmc_priv(host);
if (data) {
data->error = err;
@@ -780,6 +803,10 @@
data->bytes_xfered = 0;
else
data->bytes_xfered = blk_rq_bytes(mrq->req);
+
+ /* we're in atomic context (soft-irq) so unvote async. */
+ sdhci_msm_pm_qos_irq_unvote(sdhci_host, true);
+ cmdq_pm_qos_unvote(sdhci_host, mrq);
}
}
@@ -791,7 +818,26 @@
cmdq_runtime_pm_put(cq_host);
}
+static int cmdq_late_init(struct mmc_host *mmc)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_msm_host *msm_host = pltfm_host->priv;
+
+ /*
+ * TODO: This should basically move to something like "sdhci-cmdq-msm"
+ * for msm specific implementation.
+ */
+ sdhci_msm_pm_qos_irq_init(host);
+
+ if (msm_host->pdata->pm_qos_data.cmdq_valid)
+ sdhci_msm_pm_qos_cpu_init(host,
+ msm_host->pdata->pm_qos_data.cmdq_latency);
+ return 0;
+}
+
static const struct mmc_cmdq_host_ops cmdq_host_ops = {
+ .init = cmdq_late_init,
.enable = cmdq_enable,
.disable = cmdq_disable,
.request = cmdq_request,