From c1521a7bbac3cbf0061b2c51a344730878ea8e58 Mon Sep 17 00:00:00 2001 From: Debarshi Dutta Date: Tue, 14 Apr 2020 16:28:53 +0530 Subject: [PATCH] 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 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2328489 (cherry picked from commit 9d1e07ca184869eb0082b418d0d1cf6e62af3a40) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2330159 Reviewed-by: automaticguardword Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Deepak Nibade Reviewed-by: mobile promotions GVS: Gerrit_Virtual_Submit Tested-by: mobile promotions --- drivers/gpu/nvgpu/os/linux/module.c | 37 +++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/nvgpu/os/linux/module.c b/drivers/gpu/nvgpu/os/linux/module.c index 7e22e2878..4b70f0460 100644 --- a/drivers/gpu/nvgpu/os/linux/module.c +++ b/drivers/gpu/nvgpu/os/linux/module.c @@ -1338,11 +1338,13 @@ static int gk20a_pm_suspend(struct device *dev) struct gk20a_platform *platform = dev_get_drvdata(dev); struct gk20a *g = get_gk20a(dev); int ret = 0; - int idle_usage_count = 0; + int usage_count; + struct nvgpu_timeout timeout; if (nvgpu_is_powered_off(g)) { if (platform->suspend) ret = platform->suspend(dev); + if (ret) return ret; @@ -1352,20 +1354,43 @@ static int gk20a_pm_suspend(struct device *dev) return ret; } - if (nvgpu_atomic_read(&g->usage_count) > idle_usage_count) - return -EBUSY; + nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS, + NVGPU_TIMER_CPU_TIMER); + /* + * Hold back deterministic submits and changes to deterministic + * channels - this must be outside the power busy locks. + */ + nvgpu_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); if (ret) - return ret; + goto fail_idle; if (platform->suspend) ret = platform->suspend(dev); if (ret) - return ret; + goto fail_suspend; g->suspended = true; + return 0; + +fail_suspend: + gk20a_pm_runtime_resume(dev); +fail_idle: + nvgpu_channel_deterministic_unidle(g); return ret; } @@ -1398,6 +1423,8 @@ static int gk20a_pm_resume(struct device *dev) g->suspended = false; + nvgpu_channel_deterministic_unidle(g); + return ret; }