diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2014-07-03 17:59:39 +0530 |
---|---|---|
committer | Mandar Padmawar <mpadmawar@nvidia.com> | 2014-07-07 01:42:01 -0700 |
commit | 561dc8e0933ff2d72573292968b893a52f5f783a (patch) | |
tree | df4f45709996a9f8436597d26f4ca11f0b4b26e7 /drivers/gpu | |
parent | 45f2a14ba75e37657e37edaa18a4fa01a8562549 (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.c | 21 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/platform_gk20a.h | 1 |
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); |