summaryrefslogtreecommitdiff
path: root/drivers/gpu
diff options
context:
space:
mode:
authorDeepak Nibade <dnibade@nvidia.com>2014-07-03 17:59:39 +0530
committerMandar Padmawar <mpadmawar@nvidia.com>2014-07-07 01:42:01 -0700
commit561dc8e0933ff2d72573292968b893a52f5f783a (patch)
treedf4f45709996a9f8436597d26f4ca11f0b4b26e7 /drivers/gpu
parent45f2a14ba75e37657e37edaa18a4fa01a8562549 (diff)
gpu: nvgpu: fix race between do_idle() and unrailgate()
While we are executing do_idle() API, it is possible that unrailgate() gets invoked in midst of idling the GPU and this can result in failure of do_idle() To prevent simultaneous execution of these methods, add a mutex railgate_lock and acquire it during do_idle() and unrailgate() APIs Also, keep this lock held if do_idle() is successful. In success, lock will be released in do_unidle(), otherwise release this lock before returning Note that this lock should not be held in railgate() API since we do not want it to be blocked during do_idle() bug 1529160 Change-Id: I87114b5367eaa217376455a2699c0d21c451c889 Signed-off-by: Deepak Nibade <dnibade@nvidia.com> Reviewed-on: http://git-master/r/434190 GVS: Gerrit_Virtual_Submit Reviewed-by: Arto Merilainen <amerilainen@nvidia.com> Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Diffstat (limited to 'drivers/gpu')
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.c21
-rw-r--r--drivers/gpu/nvgpu/gk20a/platform_gk20a.h1
2 files changed, 19 insertions, 3 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c
index f3dbf31ed2b8..74138e36f5e7 100644
--- a/drivers/gpu/nvgpu/gk20a/gk20a.c
+++ b/drivers/gpu/nvgpu/gk20a/gk20a.c
@@ -1193,8 +1193,11 @@ static int gk20a_pm_unrailgate(struct generic_pm_domain *domain)
struct gk20a_platform *platform = platform_get_drvdata(g->dev);
int ret = 0;
- if (platform->unrailgate)
+ if (platform->unrailgate) {
+ mutex_lock(&platform->railgate_lock);
ret = platform->unrailgate(platform->g->dev);
+ mutex_unlock(&platform->railgate_lock);
+ }
return ret;
}
@@ -1259,6 +1262,8 @@ static int gk20a_pm_init(struct platform_device *dev)
struct gk20a_platform *platform = platform_get_drvdata(dev);
int err = 0;
+ mutex_init(&platform->railgate_lock);
+
/* Initialise pm runtime */
if (platform->clockgate_delay) {
pm_runtime_set_autosuspend_delay(&dev->dev,
@@ -1623,6 +1628,13 @@ int gk20a_do_idle(void)
/* acquire busy lock to block other busy() calls */
down_write(&g->busy_lock);
+ /* acquire railgate lock to prevent unrailgate in midst of do_idle() */
+ mutex_lock(&platform->railgate_lock);
+
+ /* check if it is already railgated ? */
+ if (platform->is_railgated(pdev))
+ return 0;
+
/* prevent suspend by incrementing usage counter */
pm_runtime_get_noresume(&pdev->dev);
@@ -1660,11 +1672,12 @@ int gk20a_do_idle(void)
}
/* GPU is not rail gated by now, return error */
- up_write(&g->busy_lock);
- return -EBUSY;
+ goto fail_timeout;
fail:
pm_runtime_put_noidle(&pdev->dev);
+fail_timeout:
+ mutex_unlock(&platform->railgate_lock);
up_write(&g->busy_lock);
return -EBUSY;
}
@@ -1678,8 +1691,10 @@ int gk20a_do_unidle(void)
bus_find_device_by_name(&platform_bus_type,
NULL, "gk20a.0"));
struct gk20a *g = get_gk20a(pdev);
+ struct gk20a_platform *platform = dev_get_drvdata(&pdev->dev);
/* release the lock and open up all other busy() calls */
+ mutex_unlock(&platform->railgate_lock);
up_write(&g->busy_lock);
return 0;
diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h
index 50358af6f11d..7ce7f95b620f 100644
--- a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h
+++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h
@@ -103,6 +103,7 @@ struct gk20a_platform {
/* Called to turn on the device */
int (*unrailgate)(struct platform_device *dev);
+ struct mutex railgate_lock;
/* Called to check state of device */
bool (*is_railgated)(struct platform_device *dev);