aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/remoteproc
diff options
context:
space:
mode:
authorFernando Guzman Lugo <fernando.lugo@ti.com>2011-11-15 15:27:27 -0600
committerIliyan Malchev <malchev@google.com>2011-11-21 13:46:34 -0800
commita9476e7910710e743fa4941e32bc508306ec1b61 (patch)
tree3e6bd637d00bad5b35136fbad4b737fcf7c8e57f /drivers/remoteproc
parent9576fc5282141a92085c9bb57363480eef649170 (diff)
downloadkernel_samsung_tuna-a9476e7910710e743fa4941e32bc508306ec1b61.tar.gz
kernel_samsung_tuna-a9476e7910710e743fa4941e32bc508306ec1b61.tar.bz2
kernel_samsung_tuna-a9476e7910710e743fa4941e32bc508306ec1b61.zip
remoteproc: protect runtime expiration time and last busy
In order to avoid a race condition between calling pm_runtime_mark_last_busy and checking the expiration time using pm_runtime_autosuspend_expiration, protect both calls using a mutex. By doing that we can do a safe check inside the runtime suspend callback for expiration time to detect a possible call to pm_runtime_mark_last_busy during runtime suspend execution and in that case abort autosuspend. Change-Id: I4608c78aefccf9c89866f9dc1ed24055d88c5546 Signed-off-by: Fernando Guzman Lugo <fernando.lugo@ti.com> Signed-off-by: Juan Gutierrez <jgutierrez@ti.com>
Diffstat (limited to 'drivers/remoteproc')
-rw-r--r--drivers/remoteproc/remoteproc.c41
1 files changed, 25 insertions, 16 deletions
diff --git a/drivers/remoteproc/remoteproc.c b/drivers/remoteproc/remoteproc.c
index 43d2fb21ccc..5d2fa6c9495 100644
--- a/drivers/remoteproc/remoteproc.c
+++ b/drivers/remoteproc/remoteproc.c
@@ -1415,31 +1415,30 @@ void rproc_last_busy(struct rproc *rproc)
{
#ifdef CONFIG_REMOTE_PROC_AUTOSUSPEND
struct device *dev = rproc->dev;
- unsigned long tj = jiffies + msecs_to_jiffies(10);
- unsigned long exp;
- /*
- * if expiration timeout is < 10msecs, cancel suspend at that
- * moment to avoid any race condition.
- */
mutex_lock(&rproc->pm_lock);
- exp = pm_runtime_autosuspend_expiration(dev);
- if (pm_runtime_suspended(dev) || !exp || time_after(tj, exp)) {
+ if (pm_runtime_suspended(dev) ||
+ !pm_runtime_autosuspend_expiration(dev)) {
+ pm_runtime_mark_last_busy(dev);
+ mutex_unlock(&rproc->pm_lock);
/*
* if the remote processor is suspended, we can not wake it
* up (that would abort system suspend), instead state that
* the remote processor needs to be waken up on system resume.
*/
+ mutex_lock(&rproc->lock);
if (rproc->state == RPROC_SUSPENDED) {
rproc->need_resume = true;
- goto unlock;
+ mutex_unlock(&rproc->lock);
+ return;
}
+ mutex_unlock(&rproc->lock);
pm_runtime_get_sync(dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
+ return;
}
pm_runtime_mark_last_busy(dev);
-unlock:
mutex_unlock(&rproc->pm_lock);
#endif
}
@@ -1454,9 +1453,9 @@ static int rproc_resume(struct device *dev)
dev_dbg(dev, "Enter %s\n", __func__);
- mutex_lock(&rproc->pm_lock);
+ mutex_lock(&rproc->lock);
if (rproc->state != RPROC_SUSPENDED) {
- mutex_unlock(&rproc->pm_lock);
+ mutex_unlock(&rproc->lock);
return 0;
}
@@ -1469,7 +1468,7 @@ static int rproc_resume(struct device *dev)
pm_runtime_put_autosuspend(dev);
unlock:
rproc->state = (ret) ? RPROC_CRASHED : RPROC_RUNNING;
- mutex_unlock(&rproc->pm_lock);
+ mutex_unlock(&rproc->lock);
if (ret) {
_event_notify(rproc, RPROC_ERROR, NULL);
dev_err(dev, "Error resuming %d\n", ret);
@@ -1485,9 +1484,9 @@ static int rproc_suspend(struct device *dev)
dev_dbg(dev, "Enter %s\n", __func__);
- mutex_lock(&rproc->pm_lock);
+ mutex_lock(&rproc->lock);
if (rproc->state != RPROC_RUNNING) {
- mutex_unlock(&rproc->pm_lock);
+ mutex_unlock(&rproc->lock);
return 0;
}
@@ -1513,7 +1512,7 @@ static int rproc_suspend(struct device *dev)
out:
if (!ret)
rproc->state = RPROC_SUSPENDED;
- mutex_unlock(&rproc->pm_lock);
+ mutex_unlock(&rproc->lock);
return ret;
}
@@ -1546,6 +1545,14 @@ static int rproc_runtime_suspend(struct device *dev)
if (rproc->state == RPROC_SUSPENDED)
return 0;
+
+ mutex_lock(&rproc->pm_lock);
+
+ if (pm_runtime_autosuspend_expiration(dev) && !rproc->force_suspend) {
+ ret = -EBUSY;
+ goto abort;
+ }
+
/*
* Notify PROC_PRE_SUSPEND only when the suspend is not forced.
* Users can use pre suspend call back to cancel autosuspend, but
@@ -1580,6 +1587,7 @@ static int rproc_runtime_suspend(struct device *dev)
}
/* we are not interested in the returned value */
_event_notify(rproc, RPROC_POS_SUSPEND, NULL);
+ mutex_unlock(&rproc->pm_lock);
return 0;
abort:
@@ -1587,6 +1595,7 @@ abort:
to = jiffies_to_msecs(pm_runtime_autosuspend_expiration(dev) - jiffies);
pm_schedule_suspend(dev, to);
dev->power.timer_autosuspends = 1;
+ mutex_unlock(&rproc->pm_lock);
return ret;
}