[PATCH v2 4/7] mmc: sh_mmcif: Use runtime PM to keep resourses active during I/O

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



While I/O operations are ongoing, make sure the runtime PM resourses
are kept active. When returning the resourses, utilize the runtime PM
autosuspend feature with a default timeout set to 50 ms.

The reason for chosing a 50 ms timeout is to make sure we are able to
handle clock gating in a future possible runtime suspend callback.
According to the (e)MMC/SD/SDIO specification the clock must be
maintained for a minimum numbers of clock cycles even after responses
has been received. 50 ms will cover all cases.

Additionally, 50 ms has for other host drivers seemed reasonable, to
prevent bringing the runtime resourses up and down between each and
every request.

Cc: Guennadi Liakhovetski <g.liakhovetski@xxxxxx>
Signed-off-by: Ulf Hansson <ulf.hansson@xxxxxxxxxx>
---
 drivers/mmc/host/sh_mmcif.c |   42 ++++++++++++++++++++++++++++--------------
 1 file changed, 28 insertions(+), 14 deletions(-)

diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c
index d032b08..f4532dc 100644
--- a/drivers/mmc/host/sh_mmcif.c
+++ b/drivers/mmc/host/sh_mmcif.c
@@ -959,6 +959,8 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
 	host->mrq = mrq;
 
+	pm_runtime_get_sync(mmc_dev(mmc));
+
 	sh_mmcif_start_cmd(host, mrq);
 }
 
@@ -1000,6 +1002,8 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	host->state = STATE_IOS;
 	spin_unlock_irqrestore(&host->lock, flags);
 
+	pm_runtime_get_sync(mmc_dev(mmc));
+
 	if (ios->power_mode == MMC_POWER_UP) {
 		if (!host->card_present) {
 			/* See if we also get DMA */
@@ -1017,20 +1021,18 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 			}
 		}
 		if (host->power) {
-			pm_runtime_put_sync(&host->pd->dev);
 			clk_disable_unprepare(host->hclk);
 			host->power = false;
 			if (ios->power_mode == MMC_POWER_OFF)
 				sh_mmcif_set_power(host, ios);
 		}
 		host->state = STATE_IDLE;
-		return;
+		goto ret;
 	}
 
 	if (ios->clock) {
 		if (!host->power) {
 			sh_mmcif_clk_update(host);
-			pm_runtime_get_sync(&host->pd->dev);
 			host->power = true;
 			sh_mmcif_sync_reset(host);
 		}
@@ -1040,6 +1042,9 @@ static void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
 	host->timing = ios->timing;
 	host->bus_width = ios->bus_width;
 	host->state = STATE_IDLE;
+ret:
+	pm_runtime_mark_last_busy(mmc_dev(mmc));
+	pm_runtime_put_autosuspend(mmc_dev(mmc));
 }
 
 static int sh_mmcif_get_cd(struct mmc_host *mmc)
@@ -1253,6 +1258,9 @@ static irqreturn_t sh_mmcif_irqt(int irq, void *dev_id)
 
 	mutex_unlock(&host->thread_lock);
 
+	pm_runtime_mark_last_busy(mmc_dev(host->mmc));
+	pm_runtime_put_autosuspend(mmc_dev(host->mmc));
+
 	return IRQ_HANDLED;
 }
 
@@ -1341,6 +1349,9 @@ static void mmcif_timeout_work(struct work_struct *work)
 	host->wait_for = MMCIF_WAIT_FOR_REQUEST;
 	host->mrq = NULL;
 	mmc_request_done(host->mmc, mrq);
+
+	pm_runtime_mark_last_busy(mmc_dev(host->mmc));
+	pm_runtime_put_autosuspend(mmc_dev(host->mmc));
 }
 
 static void sh_mmcif_init_ocr(struct sh_mmcif_host *host)
@@ -1421,23 +1432,18 @@ static int sh_mmcif_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, host);
 
-	pm_runtime_enable(&pdev->dev);
 	host->power = false;
 
 	host->hclk = clk_get(&pdev->dev, NULL);
 	if (IS_ERR(host->hclk)) {
 		ret = PTR_ERR(host->hclk);
 		dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
-		goto eclkget;
+		goto eofparse;
 	}
 	ret = sh_mmcif_clk_update(host);
 	if (ret < 0)
 		goto eclkupdate;
 
-	ret = pm_runtime_resume(&pdev->dev);
-	if (ret < 0)
-		goto eresume;
-
 	INIT_DELAYED_WORK(&host->timeout_work, mmcif_timeout_work);
 
 	sh_mmcif_sync_reset(host);
@@ -1466,6 +1472,12 @@ static int sh_mmcif_probe(struct platform_device *pdev)
 
 	mutex_init(&host->thread_lock);
 
+	pm_runtime_get_noresume(&pdev->dev);
+	pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
+	pm_runtime_use_autosuspend(&pdev->dev);
+	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_enable(&pdev->dev);
+
 	clk_disable_unprepare(host->hclk);
 	ret = mmc_add_host(mmc);
 	if (ret < 0)
@@ -1476,22 +1488,24 @@ static int sh_mmcif_probe(struct platform_device *pdev)
 	dev_info(&pdev->dev, "driver version %s\n", DRIVER_VERSION);
 	dev_dbg(&pdev->dev, "chip ver H'%04x\n",
 		sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0x0000ffff);
+
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_put_autosuspend(&pdev->dev);
+
 	return ret;
 
 emmcaddh:
+	pm_runtime_disable(&pdev->dev);
+	pm_runtime_put_noidle(&pdev->dev);
 erqcd:
 	if (irq[1] >= 0)
 		free_irq(irq[1], host);
 ereqirq1:
 	free_irq(irq[0], host);
 ereqirq0:
-	pm_runtime_suspend(&pdev->dev);
-eresume:
 	clk_disable_unprepare(host->hclk);
 eclkupdate:
 	clk_put(host->hclk);
-eclkget:
-	pm_runtime_disable(&pdev->dev);
 eofparse:
 	mmc_free_host(mmc);
 ealloch:
@@ -1532,8 +1546,8 @@ static int sh_mmcif_remove(struct platform_device *pdev)
 
 	clk_disable_unprepare(host->hclk);
 	mmc_free_host(host->mmc);
-	pm_runtime_put_sync(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
+	pm_runtime_put_noidle(&pdev->dev);
 
 	return 0;
 }
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Linux USB Devel]     [Linux Media]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux