summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDeepak Nibade <dnibade@nvidia.com>2016-10-12 05:44:15 -0400
committermobile promotions <svcmobile_promotions@nvidia.com>2016-10-18 14:08:01 -0400
commitc284516ead33708e135eeaa53672d835849f25fb (patch)
treee7ca4a1c6402f50bd1e783b78c00d92848dfc5e8
parent8b051f34fc10caa7309c0ae964fbc708d6a679a2 (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>
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.c41
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a.h1
-rw-r--r--drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c2
-rw-r--r--drivers/gpu/nvgpu/gk20a/platform_gk20a.h3
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
1422fail:
1423 if (platform->user_railgate_disabled)
1424 gk20a_busy_noresume(dev);
1425
1426 return ret;
1416} 1427}
1417 1428
1418static int gk20a_pm_resume(struct device *dev) 1429static 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
1729void gk20a_idle_nosuspend(struct device *dev)
1730{
1731 pm_runtime_put_noidle(dev);
1732}
1733
1714void gk20a_idle(struct device *dev) 1734void 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
1176void gk20a_busy_noresume(struct device *dev); 1176void gk20a_busy_noresume(struct device *dev);
1177void gk20a_idle_nosuspend(struct device *dev);
1177int __must_check gk20a_busy(struct device *dev); 1178int __must_check gk20a_busy(struct device *dev);
1178void gk20a_idle(struct device *dev); 1179void gk20a_idle(struct device *dev);
1179void gk20a_disable(struct gk20a *g, u32 units); 1180void 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