gpu: nvgpu: change system suspend's implementation

Currently, for platforms with canRailgate device characteristics disabled,
suspend can block as deterministic channels hold busy references. This
patch makes the change to first hold off any new jobs for deterministic
channels and then reverts back the busy references taken by those
channels. Following this, suspend also waits for the device to get idle
by waiting (with timeout) for the nvgpu's internal usage counter to be
come zero. This ensures there are no further jobs in progress and
allows the system to go into a suspend state.

Bug 200598228
Bug 2930266

Change-Id: Id02b4d41a9c2dd64303b2e2449dbed48c12aea4c
Signed-off-by: Debarshi Dutta <ddutta@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2328489
Reviewed-by: automaticguardword <automaticguardword@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Konsta Holtta <kholtta@nvidia.com>
Reviewed-by: Shashank Singh <shashsingh@nvidia.com>
Reviewed-by: Sami Kiminki <skiminki@nvidia.com>
Reviewed-by: Alex Waterman <alexw@nvidia.com>
Reviewed-by: Bibek Basu <bbasu@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
GVS: Gerrit_Virtual_Submit
This commit is contained in:
Debarshi Dutta
2020-04-14 16:28:53 +05:30
committed by mobile promotions
parent 06942bd268
commit 9d1e07ca18

View File

@@ -1,7 +1,7 @@
/* /*
* GK20A Graphics * GK20A Graphics
* *
* Copyright (c) 2011-2018, NVIDIA CORPORATION. All rights reserved. * Copyright (c) 2011-2020, NVIDIA CORPORATION. All rights reserved.
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -1058,11 +1058,13 @@ static int gk20a_pm_suspend(struct device *dev)
struct gk20a_platform *platform = dev_get_drvdata(dev); struct gk20a_platform *platform = dev_get_drvdata(dev);
struct gk20a *g = get_gk20a(dev); struct gk20a *g = get_gk20a(dev);
int ret = 0; int ret = 0;
int idle_usage_count = 0; int usage_count;
struct nvgpu_timeout timeout;
if (!g->power_on) { if (!g->power_on) {
if (platform->suspend) if (platform->suspend)
ret = platform->suspend(dev); ret = platform->suspend(dev);
if (ret) if (ret)
return ret; return ret;
@@ -1072,20 +1074,43 @@ static int gk20a_pm_suspend(struct device *dev)
return ret; return ret;
} }
if (nvgpu_atomic_read(&g->usage_count) > idle_usage_count) nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS,
return -EBUSY; NVGPU_TIMER_CPU_TIMER);
/*
* Hold back deterministic submits and changes to deterministic
* channels - this must be outside the power busy locks.
*/
gk20a_channel_deterministic_idle(g);
/* check and wait until GPU is idle (with a timeout) */
do {
nvgpu_usleep_range(1000, 1100);
usage_count = nvgpu_atomic_read(&g->usage_count);
} while (usage_count != 0 && !nvgpu_timeout_expired(&timeout));
if (usage_count != 0) {
nvgpu_err(g, "failed to idle - usage_count %d", usage_count);
ret = -EINVAL;
goto fail_idle;
}
ret = gk20a_pm_runtime_suspend(dev); ret = gk20a_pm_runtime_suspend(dev);
if (ret) if (ret)
return ret; goto fail_idle;
if (platform->suspend) if (platform->suspend)
ret = platform->suspend(dev); ret = platform->suspend(dev);
if (ret) if (ret)
return ret; goto fail_suspend;
g->suspended = true; g->suspended = true;
return 0;
fail_suspend:
gk20a_pm_runtime_resume(dev);
fail_idle:
gk20a_channel_deterministic_unidle(g);
return ret; return ret;
} }
@@ -1118,6 +1143,8 @@ static int gk20a_pm_resume(struct device *dev)
g->suspended = false; g->suspended = false;
gk20a_channel_deterministic_unidle(g);
return ret; return ret;
} }