]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/commitdiff
gpu: nvgpu: fix race between do_idle() and unrailgate()
authorDeepak Nibade <dnibade@nvidia.com>
Thu, 3 Jul 2014 12:29:39 +0000 (17:59 +0530)
committerMandar Padmawar <mpadmawar@nvidia.com>
Mon, 7 Jul 2014 08:42:01 +0000 (01:42 -0700)
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>
drivers/gpu/nvgpu/gk20a/gk20a.c
drivers/gpu/nvgpu/gk20a/platform_gk20a.h

index f3dbf31ed2b818c6c2e17fbd68e8b4ffe0729281..74138e36f5e786b28c5ea11a108a56d1af140d99 100644 (file)
@@ -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;
index 50358af6f11dd54f88736582b24233fa64138425..7ce7f95b620f3ec78b50abcbffaa058ed6a8ea37 100644 (file)
@@ -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);