mmc: cmdq: add platform device reference counting for runtime pm
Access to the registers of CQE HCI wrapped by increment/decrement of pm
core usage counter for the platform device.
Change-Id: I9da4aa7d28dbf8e1d2bf62f6d5fa0875bd5b6064
Signed-off-by: Konstantin Dorfman <kdorfman@codeaurora.org>
[xiaonian@codeaurora.org: fixed trivial merge conflict]
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 aa8c554..de896f0 100644
--- a/drivers/mmc/host/cmdq_hci.c
+++ b/drivers/mmc/host/cmdq_hci.c
@@ -23,6 +23,7 @@
#include <linux/mmc/mmc.h>
#include <linux/mmc/host.h>
#include <linux/mmc/card.h>
+#include <linux/pm_runtime.h>
#include "cmdq_hci.h"
@@ -32,6 +33,26 @@
/* 1 sec */
#define HALT_TIMEOUT_MS 1000
+#ifdef CONFIG_PM_RUNTIME
+static int cmdq_runtime_pm_get(struct cmdq_host *host)
+{
+ return pm_runtime_get_sync(host->mmc->parent);
+}
+static int cmdq_runtime_pm_put(struct cmdq_host *host)
+{
+ pm_runtime_mark_last_busy(host->mmc->parent);
+ return pm_runtime_put_autosuspend(host->mmc->parent);
+}
+#else
+static inline int cmdq_runtime_pm_get(struct cmdq_host *host)
+{
+ return 0;
+}
+static inline int cmdq_runtime_pm_put(struct cmdq_host *host)
+{
+ return 0;
+}
+#endif
static inline struct mmc_request *get_req_by_tag(struct cmdq_host *cq_host,
unsigned int tag)
{
@@ -272,6 +293,7 @@
if (cq_host->enabled)
goto out;
+ cmdq_runtime_pm_get(cq_host);
cqcfg = cmdq_readl(cq_host, CQCFG);
if (cqcfg & 0x1) {
pr_info("%s: %s: cq_host is already enabled\n",
@@ -335,6 +357,7 @@
cq_host->ops->clear_set_dumpregs(mmc, 1);
out:
+ cmdq_runtime_pm_put(cq_host);
return err;
}
@@ -342,12 +365,13 @@
{
struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
+ cmdq_runtime_pm_get(cq_host);
if (soft) {
cmdq_writel(cq_host, cmdq_readl(
cq_host, CQCFG) & ~(CQ_ENABLE),
CQCFG);
}
-
+ cmdq_runtime_pm_put(cq_host);
cq_host->enabled = false;
}
@@ -360,6 +384,7 @@
unsigned int rca;
int ret;
+ cmdq_runtime_pm_get(cq_host);
cqcfg = cmdq_readl(cq_host, CQCFG);
tdlba = cmdq_readl(cq_host, CQTDLBA);
tdlbau = cmdq_readl(cq_host, CQTDLBAU);
@@ -391,6 +416,7 @@
mb();
cmdq_writel(cq_host, cqcfg, CQCFG);
+ cmdq_runtime_pm_put(cq_host);
cq_host->enabled = true;
}
@@ -536,7 +562,7 @@
static int cmdq_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
- int err;
+ int err = 0;
u64 data = 0;
u64 *task_desc = NULL;
u32 tag = mrq->cmdq_req->tag;
@@ -549,11 +575,13 @@
goto out;
}
+ cmdq_runtime_pm_get(cq_host);
+
if (mrq->cmdq_req->cmdq_req_flags & DCMD) {
cmdq_prep_dcmd_desc(mmc, mrq);
cq_host->mrq_slot[DCMD_SLOT] = mrq;
cmdq_writel(cq_host, 1 << DCMD_SLOT, CQTDBR);
- return 0;
+ goto out;
}
task_desc = (__le64 __force *)get_desc(cq_host, tag);
@@ -566,7 +594,7 @@
if (err) {
pr_err("%s: %s: failed to setup tx desc: %d\n",
mmc_hostname(mmc), __func__, err);
- return err;
+ goto out;
}
BUG_ON(cmdq_readl(cq_host, CQTDBR) & (1 << tag));
@@ -578,6 +606,7 @@
cmdq_writel(cq_host, 1 << tag, CQTDBR);
out:
+ cmdq_runtime_pm_put(cq_host);
return err;
}
@@ -680,26 +709,26 @@
static int cmdq_halt(struct mmc_host *mmc, bool halt)
{
struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
- u32 val;
+ u32 ret = 0;
+ cmdq_runtime_pm_get(cq_host);
if (halt) {
cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) | HALT,
CQCTL);
- val = wait_for_completion_timeout(&cq_host->halt_comp,
+ ret = wait_for_completion_timeout(&cq_host->halt_comp,
msecs_to_jiffies(HALT_TIMEOUT_MS));
/* halt done: re-enable legacy interrupts */
if (cq_host->ops->clear_set_irqs)
cq_host->ops->clear_set_irqs(mmc, false);
-
- return val ? 0 : -ETIMEDOUT;
+ ret = ret ? 0 : -ETIMEDOUT;
} else {
if (cq_host->ops->clear_set_irqs)
cq_host->ops->clear_set_irqs(mmc, true);
cmdq_writel(cq_host, cmdq_readl(cq_host, CQCTL) & ~HALT,
CQCTL);
}
-
- return 0;
+ cmdq_runtime_pm_put(cq_host);
+ return ret;
}
static void cmdq_post_req(struct mmc_host *host, struct mmc_request *mrq,
@@ -722,8 +751,9 @@
static void cmdq_dumpstate(struct mmc_host *mmc)
{
struct cmdq_host *cq_host = (struct cmdq_host *)mmc_cmdq_private(mmc);
-
+ cmdq_runtime_pm_get(cq_host);
cmdq_dumpregs(cq_host);
+ cmdq_runtime_pm_put(cq_host);
}
static const struct mmc_cmdq_host_ops cmdq_host_ops = {