gpu: nvgpu: do_idle/unidle handling with runtime PM after probe

Extend the runtime suspend/resume based idle/unidle logic in the
probe case to handling done in gk20a_do_idle/unidle for nvgpu
after the probe completion.

If the railgating is disabled, setting autosuspend_delay to 0 will
enable the suspend. If railgating is enabled, autosuspend delay
will be > 0. Setting it to 0 will enable the immediate suspend.

With this approach based on RPM, forced_reset logic is removed.
force_reset_in_do_idle is also removed as railgating is
supported.

Bug 200602747
JIRA NVGPU-5356

Change-Id: Iaf6d5ab651b8200f0547b45d90f812110cf63c0e
Signed-off-by: Sagar Kamble <skamble@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2375941
GVS: Gerrit_Virtual_Submit
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Reviewed-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-by: Sachin Nikam <snikam@nvidia.com>
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Sagar Kamble
2020-07-15 13:18:46 +05:30
committed by Alex Waterman
parent 4012a97640
commit bd7bda4f98
6 changed files with 45 additions and 128 deletions

View File

@@ -745,24 +745,23 @@ MODULE_DEVICE_TABLE(of, tegra_gk20a_of_match);
#ifdef CONFIG_PM
/**
* gk20a_do_idle_impl() - force the GPU to idle and railgate
* gk20a_do_idle() - force the GPU to idle and railgate
*
* In success, this call MUST be balanced by caller with gk20a_do_unidle_impl()
* In success, this call MUST be balanced by caller with gk20a_do_unidle()
*
* Acquires two locks : &l->busy_lock and &platform->railgate_lock
* In success, we hold these locks and return
* In failure, we release these locks and return
*/
int gk20a_do_idle_impl(struct gk20a *g, bool force_reset)
int gk20a_do_idle(void *_g)
{
struct gk20a *g = (struct gk20a *)_g;
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
struct device *dev = dev_from_gk20a(g);
struct gk20a_platform *platform = dev_get_drvdata(dev);
struct nvgpu_timeout timeout;
int ref_cnt;
int target_ref_cnt = 0;
bool is_railgated;
int err = 0;
if (!g->probe_done) {
/*
@@ -812,6 +811,7 @@ int gk20a_do_idle_impl(struct gk20a *g, bool force_reset)
target_ref_cnt = 1;
else
target_ref_cnt = 2;
nvgpu_mutex_acquire(&platform->railgate_lock);
nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS,
@@ -826,100 +826,47 @@ int gk20a_do_idle_impl(struct gk20a *g, bool force_reset)
if (ref_cnt != target_ref_cnt) {
nvgpu_err(g, "failed to idle - refcount %d != target_ref_cnt",
ref_cnt);
goto fail_drop_usage_count;
pm_runtime_put_noidle(dev);
nvgpu_mutex_release(&platform->railgate_lock);
up_write(&l->busy_lock);
nvgpu_channel_deterministic_unidle(g);
return -EBUSY;
}
/* check if global force_reset flag is set */
force_reset |= platform->force_reset_in_do_idle;
/*
* If railgating is enabled, autosuspend delay will be > 0. Set it to
* 0 to suspend immediately. If railgating is disabled setting it to
* 0 will reduce the usage count. pm_runtime_put_sync_autosuspend
* will then suspend immediately.
*/
pm_runtime_set_autosuspend_delay(dev, 0);
nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS,
NVGPU_TIMER_CPU_TIMER);
pm_runtime_put_sync_autosuspend(dev);
if (nvgpu_is_enabled(g, NVGPU_CAN_RAILGATE) && !force_reset) {
/*
* Case 1 : GPU railgate is supported
*
* if GPU is now idle, we will have only one ref count,
* drop this ref which will rail gate the GPU
*/
pm_runtime_put_sync(dev);
/* add sufficient delay to allow GPU to rail gate */
nvgpu_msleep(g->railgate_delay);
/* check in loop if GPU is railgated or not */
do {
nvgpu_usleep_range(1000, 1100);
is_railgated = platform->is_railgated(dev);
} while (!is_railgated && !nvgpu_timeout_expired(&timeout));
if (is_railgated) {
return 0;
} else {
nvgpu_err(g, "failed to idle in timeout");
goto fail_timeout;
}
} else {
/*
* Case 2 : GPU railgate is not supported or we explicitly
* do not want to depend on runtime PM
*
* if GPU is now idle, call prepare_poweroff() to save the
* state and then do explicit railgate
*
* gk20a_do_unidle_impl() needs to unrailgate, call
* finalize_poweron(), and then call pm_runtime_put_sync()
* to balance the GPU usage counter
*/
/* Save the GPU state */
err = gk20a_pm_prepare_poweroff(dev);
if (err)
goto fail_drop_usage_count;
/* railgate GPU */
platform->railgate(dev);
nvgpu_udelay(10);
g->forced_reset = true;
if (pm_runtime_status_suspended(dev)) {
return 0;
} else {
nvgpu_err(g, "failed to idle in timeout");
/*
* gk20a_do_unidle will release the locks and reset the
* autosuspend delay.
*/
(void) gk20a_do_unidle(g);
return -EBUSY;
}
fail_drop_usage_count:
pm_runtime_put_noidle(dev);
fail_timeout:
nvgpu_mutex_release(&platform->railgate_lock);
up_write(&l->busy_lock);
nvgpu_channel_deterministic_unidle(g);
return -EBUSY;
}
#ifdef CONFIG_NVGPU_VPR
/**
* gk20a_do_idle() - wrap up for gk20a_do_idle_impl() to be called
* from outside of GPU driver
*
* In success, this call MUST be balanced by caller with gk20a_do_unidle()
* gk20a_do_unidle() - unblock all the tasks blocked by gk20a_do_idle()
*/
int gk20a_do_idle(void *_g)
int gk20a_do_unidle(void *_g)
{
struct gk20a *g = (struct gk20a *)_g;
return gk20a_do_idle_impl(g, true);
}
#endif
/**
* gk20a_do_unidle_impl() - unblock all the tasks blocked by
* gk20a_do_idle_impl()
*/
int gk20a_do_unidle_impl(struct gk20a *g)
{
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
struct device *dev = dev_from_gk20a(g);
struct gk20a_platform *platform = dev_get_drvdata(dev);
int err;
if (!g->probe_done) {
pm_runtime_get_sync(dev);
@@ -931,44 +878,25 @@ int gk20a_do_unidle_impl(struct gk20a *g)
}
}
if (g->forced_reset) {
/*
* If we did a forced-reset/railgate
* then unrailgate the GPU here first
*/
platform->unrailgate(dev);
/*
* Release the railgate_lock here as setting autosuspend_delay to -1
* resumes the device that needs this lock.
*/
nvgpu_mutex_release(&platform->railgate_lock);
/* restore the GPU state */
err = gk20a_pm_finalize_poweron(dev);
if (err)
return err;
/* balance GPU usage counter */
pm_runtime_put_sync(dev);
g->forced_reset = false;
}
if (g->railgate_delay && nvgpu_is_enabled(g, NVGPU_CAN_RAILGATE))
pm_runtime_set_autosuspend_delay(dev,
g->railgate_delay);
else
pm_runtime_set_autosuspend_delay(dev, -1);
/* release the lock and open up all other busy() calls */
nvgpu_mutex_release(&platform->railgate_lock);
up_write(&l->busy_lock);
nvgpu_channel_deterministic_unidle(g);
return 0;
}
#ifdef CONFIG_NVGPU_VPR
/**
* gk20a_do_unidle() - wrap up for gk20a_do_unidle_impl()
*/
int gk20a_do_unidle(void *_g)
{
struct gk20a *g = (struct gk20a *)_g;
return gk20a_do_unidle_impl(g);
}
#endif
#endif
void __iomem *nvgpu_devm_ioremap_resource(struct platform_device *dev, int i,