diff options
author | Deepak Nibade <dnibade@nvidia.com> | 2016-10-12 05:44:15 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2016-10-18 14:08:01 -0400 |
commit | c284516ead33708e135eeaa53672d835849f25fb (patch) | |
tree | e7ca4a1c6402f50bd1e783b78c00d92848dfc5e8 /drivers/gpu/nvgpu | |
parent | 8b051f34fc10caa7309c0ae964fbc708d6a679a2 (diff) |
gpu: nvgpu: support suspend/resume with user disabled railgating
We take an extra power refcount when we disable railgating
through railgate_enable sysfs
And that breaks suspend/resume since we check for power
refcount first in gk20a_pm_suspend()
Fix this with following :
- set a flag user_railgate_disabled when User
disables railgating through sysfs railgate_enable
- in gk20a_pm_suspend(), drop one power refcount
if flag is set
- in gk20a_pm_resume(), take one refcount again
if flag is set
Fix __gk20a_do_idle() to consider this extra refcount as well.
Add new variable target_ref_cnt and use it instead of
assuming target refcount of 1
In case User has disabled rail gating, set this target
refcount as 2
Also, export gk20a_idle_nosuspend() which drop power refcount
without triggering suspend
Bug 200233570
Change-Id: Ic0e35c73eb74ffefea1cd90d1b152650d9d2043d
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/1236047
(cherry picked from commit 6e002d57da4b5c58ed79889728bb678d3aa1f1b1)
Reviewed-on: http://git-master/r/1235219
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu')
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.c | 41 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a.h | 1 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c | 2 | ||||
-rw-r--r-- | drivers/gpu/nvgpu/gk20a/platform_gk20a.h | 3 |
4 files changed, 42 insertions, 5 deletions
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.c b/drivers/gpu/nvgpu/gk20a/gk20a.c index 721c44e3..ff87edc2 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a.c | |||
@@ -1395,9 +1395,14 @@ static int gk20a_pm_suspend(struct device *dev) | |||
1395 | struct gk20a *g = get_gk20a(dev); | 1395 | struct gk20a *g = get_gk20a(dev); |
1396 | int ret = 0; | 1396 | int ret = 0; |
1397 | 1397 | ||
1398 | if (platform->user_railgate_disabled) | ||
1399 | gk20a_idle_nosuspend(dev); | ||
1400 | |||
1398 | #ifdef CONFIG_PM | 1401 | #ifdef CONFIG_PM |
1399 | if (atomic_read(&dev->power.usage_count) > 1) | 1402 | if (atomic_read(&dev->power.usage_count) > 1) { |
1400 | return -EBUSY; | 1403 | ret = -EBUSY; |
1404 | goto fail; | ||
1405 | } | ||
1401 | #endif | 1406 | #endif |
1402 | 1407 | ||
1403 | if (!g->power_on) | 1408 | if (!g->power_on) |
@@ -1405,7 +1410,7 @@ static int gk20a_pm_suspend(struct device *dev) | |||
1405 | 1410 | ||
1406 | ret = gk20a_pm_runtime_suspend(dev); | 1411 | ret = gk20a_pm_runtime_suspend(dev); |
1407 | if (ret) | 1412 | if (ret) |
1408 | return ret; | 1413 | goto fail; |
1409 | 1414 | ||
1410 | if (platform->suspend) | 1415 | if (platform->suspend) |
1411 | platform->suspend(dev); | 1416 | platform->suspend(dev); |
@@ -1413,13 +1418,23 @@ static int gk20a_pm_suspend(struct device *dev) | |||
1413 | g->suspended = true; | 1418 | g->suspended = true; |
1414 | 1419 | ||
1415 | return 0; | 1420 | return 0; |
1421 | |||
1422 | fail: | ||
1423 | if (platform->user_railgate_disabled) | ||
1424 | gk20a_busy_noresume(dev); | ||
1425 | |||
1426 | return ret; | ||
1416 | } | 1427 | } |
1417 | 1428 | ||
1418 | static int gk20a_pm_resume(struct device *dev) | 1429 | static int gk20a_pm_resume(struct device *dev) |
1419 | { | 1430 | { |
1420 | struct gk20a *g = get_gk20a(dev); | 1431 | struct gk20a *g = get_gk20a(dev); |
1432 | struct gk20a_platform *platform = dev_get_drvdata(dev); | ||
1421 | int ret = 0; | 1433 | int ret = 0; |
1422 | 1434 | ||
1435 | if (platform->user_railgate_disabled) | ||
1436 | gk20a_busy_noresume(dev); | ||
1437 | |||
1423 | if (!g->suspended) | 1438 | if (!g->suspended) |
1424 | return 0; | 1439 | return 0; |
1425 | 1440 | ||
@@ -1711,6 +1726,11 @@ fail: | |||
1711 | return ret < 0 ? ret : 0; | 1726 | return ret < 0 ? ret : 0; |
1712 | } | 1727 | } |
1713 | 1728 | ||
1729 | void gk20a_idle_nosuspend(struct device *dev) | ||
1730 | { | ||
1731 | pm_runtime_put_noidle(dev); | ||
1732 | } | ||
1733 | |||
1714 | void gk20a_idle(struct device *dev) | 1734 | void gk20a_idle(struct device *dev) |
1715 | { | 1735 | { |
1716 | if (pm_runtime_enabled(dev)) { | 1736 | if (pm_runtime_enabled(dev)) { |
@@ -1783,6 +1803,7 @@ int __gk20a_do_idle(struct device *dev, bool force_reset) | |||
1783 | unsigned long timeout = jiffies + | 1803 | unsigned long timeout = jiffies + |
1784 | msecs_to_jiffies(GK20A_WAIT_FOR_IDLE_MS); | 1804 | msecs_to_jiffies(GK20A_WAIT_FOR_IDLE_MS); |
1785 | int ref_cnt; | 1805 | int ref_cnt; |
1806 | int target_ref_cnt = 0; | ||
1786 | bool is_railgated; | 1807 | bool is_railgated; |
1787 | int err = 0; | 1808 | int err = 0; |
1788 | 1809 | ||
@@ -1802,15 +1823,25 @@ int __gk20a_do_idle(struct device *dev, bool force_reset) | |||
1802 | */ | 1823 | */ |
1803 | mutex_unlock(&platform->railgate_lock); | 1824 | mutex_unlock(&platform->railgate_lock); |
1804 | pm_runtime_get_sync(dev); | 1825 | pm_runtime_get_sync(dev); |
1826 | |||
1827 | /* | ||
1828 | * One refcount taken in this API | ||
1829 | * If User disables rail gating, we take one more | ||
1830 | * extra refcount | ||
1831 | */ | ||
1832 | if (platform->user_railgate_disabled) | ||
1833 | target_ref_cnt = 2; | ||
1834 | else | ||
1835 | target_ref_cnt = 1; | ||
1805 | mutex_lock(&platform->railgate_lock); | 1836 | mutex_lock(&platform->railgate_lock); |
1806 | 1837 | ||
1807 | /* check and wait until GPU is idle (with a timeout) */ | 1838 | /* check and wait until GPU is idle (with a timeout) */ |
1808 | do { | 1839 | do { |
1809 | msleep(1); | 1840 | msleep(1); |
1810 | ref_cnt = atomic_read(&dev->power.usage_count); | 1841 | ref_cnt = atomic_read(&dev->power.usage_count); |
1811 | } while (ref_cnt != 1 && time_before(jiffies, timeout)); | 1842 | } while (ref_cnt != target_ref_cnt && time_before(jiffies, timeout)); |
1812 | 1843 | ||
1813 | if (ref_cnt != 1) { | 1844 | if (ref_cnt != target_ref_cnt) { |
1814 | gk20a_err(dev, "failed to idle - refcount %d != 1\n", | 1845 | gk20a_err(dev, "failed to idle - refcount %d != 1\n", |
1815 | ref_cnt); | 1846 | ref_cnt); |
1816 | goto fail_drop_usage_count; | 1847 | goto fail_drop_usage_count; |
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 8e0072de..d51fdea1 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h | |||
@@ -1174,6 +1174,7 @@ void gk20a_remove_sysfs(struct device *dev); | |||
1174 | #define GK20A_SIM_IORESOURCE_MEM 2 | 1174 | #define GK20A_SIM_IORESOURCE_MEM 2 |
1175 | 1175 | ||
1176 | void gk20a_busy_noresume(struct device *dev); | 1176 | void gk20a_busy_noresume(struct device *dev); |
1177 | void gk20a_idle_nosuspend(struct device *dev); | ||
1177 | int __must_check gk20a_busy(struct device *dev); | 1178 | int __must_check gk20a_busy(struct device *dev); |
1178 | void gk20a_idle(struct device *dev); | 1179 | void gk20a_idle(struct device *dev); |
1179 | void gk20a_disable(struct gk20a *g, u32 units); | 1180 | void gk20a_disable(struct gk20a *g, u32 units); |
diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c index 875a99ce..a79ec201 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c | |||
@@ -294,12 +294,14 @@ static ssize_t railgate_enable_store(struct device *dev, | |||
294 | /* release extra ref count */ | 294 | /* release extra ref count */ |
295 | gk20a_idle(dev); | 295 | gk20a_idle(dev); |
296 | platform->can_railgate = true; | 296 | platform->can_railgate = true; |
297 | platform->user_railgate_disabled = false; | ||
297 | } else if (railgate_enable == 0 && platform->can_railgate) { | 298 | } else if (railgate_enable == 0 && platform->can_railgate) { |
298 | /* take extra ref count */ | 299 | /* take extra ref count */ |
299 | err = gk20a_busy(dev); | 300 | err = gk20a_busy(dev); |
300 | if (err) | 301 | if (err) |
301 | return err; | 302 | return err; |
302 | platform->can_railgate = false; | 303 | platform->can_railgate = false; |
304 | platform->user_railgate_disabled = true; | ||
303 | } | 305 | } |
304 | if (err) | 306 | if (err) |
305 | return err; | 307 | return err; |
diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h index f038b072..6afd4852 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h | |||
@@ -44,6 +44,9 @@ struct gk20a_platform { | |||
44 | /* Should be populated at probe. */ | 44 | /* Should be populated at probe. */ |
45 | bool can_railgate; | 45 | bool can_railgate; |
46 | 46 | ||
47 | /* Set by User while disabling railgating */ | ||
48 | bool user_railgate_disabled; | ||
49 | |||
47 | /* Should be populated at probe. */ | 50 | /* Should be populated at probe. */ |
48 | bool can_elpg; | 51 | bool can_elpg; |
49 | 52 | ||