mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
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:
committed by
Alex Waterman
parent
4012a97640
commit
bd7bda4f98
@@ -390,7 +390,6 @@ struct gk20a {
|
||||
bool can_elpg;
|
||||
bool mscg_enabled;
|
||||
bool forced_idle;
|
||||
bool forced_reset;
|
||||
bool allow_all;
|
||||
|
||||
u32 ptimer_src_freq;
|
||||
@@ -681,8 +680,8 @@ int gk20a_do_unidle(void *_g);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
int gk20a_do_idle_impl(struct gk20a *g, bool force_reset);
|
||||
int gk20a_do_unidle_impl(struct gk20a *g);
|
||||
int gk20a_do_idle(void *_g);
|
||||
int gk20a_do_unidle(void *_g);
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/* check if global force_reset flag is set */
|
||||
force_reset |= platform->force_reset_in_do_idle;
|
||||
|
||||
nvgpu_timeout_init(g, &timeout, GK20A_WAIT_FOR_IDLE_MS,
|
||||
NVGPU_TIMER_CPU_TIMER);
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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()
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
int gk20a_do_idle(void *_g)
|
||||
pm_runtime_set_autosuspend_delay(dev, 0);
|
||||
|
||||
pm_runtime_put_sync_autosuspend(dev);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gk20a_do_unidle() - unblock all the tasks blocked by gk20a_do_idle()
|
||||
*/
|
||||
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
|
||||
* Release the railgate_lock here as setting autosuspend_delay to -1
|
||||
* resumes the device that needs this lock.
|
||||
*/
|
||||
platform->unrailgate(dev);
|
||||
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,
|
||||
|
||||
@@ -154,12 +154,6 @@ struct gk20a_platform {
|
||||
/* Disable nvlink support */
|
||||
bool disable_nvlink;
|
||||
|
||||
/*
|
||||
* gk20a_do_idle() API can take GPU either into rail gate or CAR reset
|
||||
* This flag can be used to force CAR reset case instead of rail gate
|
||||
*/
|
||||
bool force_reset_in_do_idle;
|
||||
|
||||
/* guest/vm id, needed for IPA to PA transation */
|
||||
int vmid;
|
||||
|
||||
|
||||
@@ -981,8 +981,6 @@ struct gk20a_platform gm20b_tegra_platform = {
|
||||
.enable_perfmon = true,
|
||||
.ptimer_src_freq = 19200000,
|
||||
|
||||
.force_reset_in_do_idle = false,
|
||||
|
||||
.ch_wdt_init_limit_ms = 5000,
|
||||
|
||||
.probe = gk20a_tegra_probe,
|
||||
|
||||
@@ -585,8 +585,6 @@ struct gk20a_platform gp10b_tegra_platform = {
|
||||
.reset_assert = gp10b_tegra_reset_assert,
|
||||
.reset_deassert = gp10b_tegra_reset_deassert,
|
||||
|
||||
.force_reset_in_do_idle = false,
|
||||
|
||||
.platform_chip_id = TEGRA_186,
|
||||
.soc_name = "tegra18x",
|
||||
|
||||
|
||||
@@ -788,7 +788,7 @@ static ssize_t force_idle_store(struct device *dev,
|
||||
if (g->forced_idle)
|
||||
return count; /* do nothing */
|
||||
else {
|
||||
err = gk20a_do_idle_impl(g, false);
|
||||
err = gk20a_do_idle(g);
|
||||
if (!err) {
|
||||
g->forced_idle = 1;
|
||||
nvgpu_info(g, "gpu is idle : %d",
|
||||
@@ -799,7 +799,7 @@ static ssize_t force_idle_store(struct device *dev,
|
||||
if (!g->forced_idle)
|
||||
return count; /* do nothing */
|
||||
else {
|
||||
err = gk20a_do_unidle_impl(g);
|
||||
err = gk20a_do_unidle(g);
|
||||
if (!err) {
|
||||
g->forced_idle = 0;
|
||||
nvgpu_info(g, "gpu is idle : %d",
|
||||
|
||||
Reference in New Issue
Block a user