diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2014-07-03 08:29:39 -0400 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2015-03-18 15:10:24 -0400 |
commit | 0b1f9e427205190dc5e651f78ff7f8be8641037e (patch) | |
tree | 9d202f8c4a89fec720de139f28d41e58210dedef | |
parent | d608aa53ee338922cbd47ec144cd6efb36fd0295 (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
(cherry picked from commit 561dc8e0933ff2d72573292968b893a52f5f783a)
Reviewed-on: http://git-master/r/435131
Reviewed-by: Arto Merilainen <amerilainen@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.c | 23 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/platform_gk20a.h | 1 |
2 files changed, 21 insertions, 3 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index 629423c0..64be9398 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c | |||
@@ -1281,8 +1281,13 @@ static int _gk20a_pm_unrailgate(struct platform_device *pdev) | |||
1281 | { | 1281 | { |
1282 | struct gk20a_platform *platform = platform_get_drvdata(pdev); | 1282 | struct gk20a_platform *platform = platform_get_drvdata(pdev); |
1283 | int ret = 0; | 1283 | int ret = 0; |
1284 | if (platform->unrailgate) | 1284 | |
1285 | if (platform->unrailgate) { | ||
1286 | mutex_lock(&platform->railgate_lock); | ||
1285 | ret = platform->unrailgate(pdev); | 1287 | ret = platform->unrailgate(pdev); |
1288 | mutex_unlock(&platform->railgate_lock); | ||
1289 | } | ||
1290 | |||
1286 | return ret; | 1291 | return ret; |
1287 | } | 1292 | } |
1288 | 1293 | ||
@@ -1362,6 +1367,8 @@ static int gk20a_pm_init(struct platform_device *dev) | |||
1362 | 1367 | ||
1363 | gk20a_dbg_fn(""); | 1368 | gk20a_dbg_fn(""); |
1364 | 1369 | ||
1370 | mutex_init(&platform->railgate_lock); | ||
1371 | |||
1365 | /* Initialise pm runtime */ | 1372 | /* Initialise pm runtime */ |
1366 | if (platform->clockgate_delay) { | 1373 | if (platform->clockgate_delay) { |
1367 | pm_runtime_set_autosuspend_delay(&dev->dev, | 1374 | pm_runtime_set_autosuspend_delay(&dev->dev, |
@@ -1739,6 +1746,13 @@ int gk20a_do_idle(void) | |||
1739 | /* acquire busy lock to block other busy() calls */ | 1746 | /* acquire busy lock to block other busy() calls */ |
1740 | down_write(&g->busy_lock); | 1747 | down_write(&g->busy_lock); |
1741 | 1748 | ||
1749 | /* acquire railgate lock to prevent unrailgate in midst of do_idle() */ | ||
1750 | mutex_lock(&platform->railgate_lock); | ||
1751 | |||
1752 | /* check if it is already railgated ? */ | ||
1753 | if (platform->is_railgated(pdev)) | ||
1754 | return 0; | ||
1755 | |||
1742 | /* prevent suspend by incrementing usage counter */ | 1756 | /* prevent suspend by incrementing usage counter */ |
1743 | pm_runtime_get_noresume(&pdev->dev); | 1757 | pm_runtime_get_noresume(&pdev->dev); |
1744 | 1758 | ||
@@ -1776,11 +1790,12 @@ int gk20a_do_idle(void) | |||
1776 | } | 1790 | } |
1777 | 1791 | ||
1778 | /* GPU is not rail gated by now, return error */ | 1792 | /* GPU is not rail gated by now, return error */ |
1779 | up_write(&g->busy_lock); | 1793 | goto fail_timeout; |
1780 | return -EBUSY; | ||
1781 | 1794 | ||
1782 | fail: | 1795 | fail: |
1783 | pm_runtime_put_noidle(&pdev->dev); | 1796 | pm_runtime_put_noidle(&pdev->dev); |
1797 | fail_timeout: | ||
1798 | mutex_unlock(&platform->railgate_lock); | ||
1784 | up_write(&g->busy_lock); | 1799 | up_write(&g->busy_lock); |
1785 | return -EBUSY; | 1800 | return -EBUSY; |
1786 | } | 1801 | } |
@@ -1794,8 +1809,10 @@ int gk20a_do_unidle(void) | |||
1794 | bus_find_device_by_name(&platform_bus_type, | 1809 | bus_find_device_by_name(&platform_bus_type, |
1795 | NULL, "gk20a.0")); | 1810 | NULL, "gk20a.0")); |
1796 | struct gk20a *g = get_gk20a(pdev); | 1811 | struct gk20a *g = get_gk20a(pdev); |
1812 | struct gk20a_platform *platform = dev_get_drvdata(&pdev->dev); | ||
1797 | 1813 | ||
1798 | /* release the lock and open up all other busy() calls */ | 1814 | /* release the lock and open up all other busy() calls */ |
1815 | mutex_unlock(&platform->railgate_lock); | ||
1799 | up_write(&g->busy_lock); | 1816 | up_write(&g->busy_lock); |
1800 | 1817 | ||
1801 | return 0; | 1818 | return 0; |
diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h index 231f97b3..76e9cf6c 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h | |||
@@ -118,6 +118,7 @@ struct gk20a_platform { | |||
118 | 118 | ||
119 | /* Called to turn on the device */ | 119 | /* Called to turn on the device */ |
120 | int (*unrailgate)(struct platform_device *dev); | 120 | int (*unrailgate)(struct platform_device *dev); |
121 | struct mutex railgate_lock; | ||
121 | 122 | ||
122 | /* Called to check state of device */ | 123 | /* Called to check state of device */ |
123 | bool (*is_railgated)(struct platform_device *dev); | 124 | bool (*is_railgated)(struct platform_device *dev); |