gpu: nvgpu: simplify power management

We currenlty initialize both runtime PM and pm_domains frameworks
and use pm_domain to control runtime power management of NvGPU

But since GPU has a separate rail, using pm_domain is not
strictly required
Hence remove pm_domain support and use runtime PM only for all
the power management
This also simplifies the code a lot

Initialization in gk20a_pm_init()
- if railgate_delay is set, set autosuspend delay of runtime PM
- try enabling runtime PM
- if runtime PM is now enabled, keep GPU railgated
- if runtime PM is not enabled, keep GPU unrailgated
- if can_railgate = false, disable runtime PM and keep
  GPU unrailgated

Set gk20a_pm_ops with below callbacks for runtime PM
static const struct dev_pm_ops gk20a_pm_ops = {
.runtime_resume = gk20a_pm_runtime_resume,
.runtime_suspend = gk20a_pm_runtime_suspend,
.resume = gk20a_pm_resume,
.suspend = gk20a_pm_suspend,
}

Move gk20a_busy() to use runtime checks of pm_runtime_enabled()
instead of using compile time checks on CONFIG_PM

Clean up some pm_domain related code

Remove use of gk20a_pm_enable/disable_clk() since this
should be already done in platform specific unrailgate()/
railgate() APIs

Fix "railgate_delay" and "railgate_enable" sysfs to use
runtime PM calls

For VGPU, disable runtime PM during vgpu_pm_init()
With this, we will initialize vgpu with vgpu_pm_finalize_poweron()
upon first call to gk20a_busy()

Jira DNVGPU-57

Change-Id: I6013e33ae9bd28f35c25271af1239942a4fa0919
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/1163216
Reviewed-by: Automatic_Commit_Validation_User
GVS: Gerrit_Virtual_Submit
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
Deepak Nibade
2016-06-09 18:46:21 +05:30
committed by Terje Bergstrom
parent 8417698b51
commit e27c72446b
6 changed files with 126 additions and 355 deletions

View File

@@ -36,7 +36,6 @@
#include <linux/debugfs.h>
#include <linux/spinlock.h>
#include <linux/tegra-powergate.h>
#include <linux/tegra_pm_domains.h>
#include <linux/clk/tegra.h>
#include <linux/kthread.h>
#include <linux/platform/tegra/common.h>
@@ -1130,41 +1129,31 @@ struct channel_gk20a *gk20a_get_channel_from_file(int fd)
return ch;
}
static int gk20a_pm_enable_clk(struct device *dev)
static int gk20a_pm_railgate(struct device *dev)
{
int index = 0;
struct gk20a_platform *platform;
struct gk20a_platform *platform = dev_get_drvdata(dev);
int ret = 0;
platform = dev_get_drvdata(dev);
if (!platform)
return -EINVAL;
if (platform->railgate)
ret = platform->railgate(dev);
for (index = 0; index < platform->num_clks; index++) {
int err = 0;
if (platform->clk[index])
err = clk_prepare_enable(platform->clk[index]);
if (err)
return -EINVAL;
}
return 0;
return ret;
}
static int gk20a_pm_disable_clk(struct device *dev)
static int gk20a_pm_unrailgate(struct device *dev)
{
int index = 0;
struct gk20a_platform *platform;
struct gk20a_platform *platform = dev_get_drvdata(dev);
int ret = 0;
platform = dev_get_drvdata(dev);
if (!platform)
return -EINVAL;
trace_gk20a_pm_unrailgate(dev_name(dev));
for (index = 0; index < platform->num_clks; index++) {
if (platform->clk[index])
clk_disable_unprepare(platform->clk[index]);
if (platform->unrailgate) {
mutex_lock(&platform->railgate_lock);
ret = platform->unrailgate(dev);
mutex_unlock(&platform->railgate_lock);
}
return 0;
return ret;
}
static void gk20a_pm_shutdown(struct platform_device *pdev)
@@ -1176,17 +1165,12 @@ static void gk20a_pm_shutdown(struct platform_device *pdev)
/* If GPU is already railgated,
* just prevent more requests, and return */
if (platform->is_railgated && platform->is_railgated(&pdev->dev)) {
#ifdef CONFIG_PM
__pm_runtime_disable(&pdev->dev, false);
#endif
return;
}
#ifdef CONFIG_PM
/* Prevent more requests by disabling Runtime PM */
__pm_runtime_disable(&pdev->dev, false);
#endif
/* Be ready for rail-gate after this point */
if (gk20a_gpu_is_virtual(&pdev->dev))
@@ -1194,63 +1178,55 @@ static void gk20a_pm_shutdown(struct platform_device *pdev)
else
gk20a_pm_prepare_poweroff(&pdev->dev);
gk20a_pm_railgate(&pdev->dev);
dev_info(&pdev->dev, "shut down complete\n");
}
#ifdef CONFIG_PM
static const struct dev_pm_ops gk20a_pm_ops = {
#if defined(CONFIG_PM) && !defined(CONFIG_PM_GENERIC_DOMAINS)
.runtime_resume = gk20a_pm_enable_clk,
.runtime_suspend = gk20a_pm_disable_clk,
#endif
};
#endif
static int _gk20a_pm_railgate(struct device *dev)
static int gk20a_pm_runtime_resume(struct device *dev)
{
struct gk20a_platform *platform = dev_get_drvdata(dev);
int ret = 0;
if (platform->railgate)
ret = platform->railgate(dev);
return ret;
int err = 0;
err = gk20a_pm_unrailgate(dev);
if (err)
goto fail;
err = gk20a_pm_finalize_poweron(dev);
if (err)
goto fail_poweron;
return 0;
fail_poweron:
gk20a_pm_railgate(dev);
fail:
return err;
}
static int gk20a_pm_railgate(struct generic_pm_domain *domain)
static int gk20a_pm_runtime_suspend(struct device *dev)
{
struct gk20a_domain_data *gk20a_domain = container_of(domain,
struct gk20a_domain_data, gpd);
struct gk20a *g = gk20a_domain->gk20a;
int err = 0;
return _gk20a_pm_railgate(g->dev);
}
err = gk20a_pm_prepare_poweroff(dev);
if (err)
goto fail;
static int _gk20a_pm_unrailgate(struct device *dev)
{
struct gk20a_platform *platform = dev_get_drvdata(dev);
int ret = 0;
err = gk20a_pm_railgate(dev);
if (err)
goto fail_railgate;
if (platform->unrailgate) {
mutex_lock(&platform->railgate_lock);
ret = platform->unrailgate(dev);
mutex_unlock(&platform->railgate_lock);
}
return 0;
return ret;
}
static int gk20a_pm_unrailgate(struct generic_pm_domain *domain)
{
struct gk20a_domain_data *gk20a_domain = container_of(domain,
struct gk20a_domain_data, gpd);
struct gk20a *g = gk20a_domain->gk20a;
trace_gk20a_pm_unrailgate(dev_name(g->dev));
return _gk20a_pm_unrailgate(g->dev);
fail_railgate:
gk20a_pm_finalize_poweron(dev);
fail:
return err;
}
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;
#ifdef CONFIG_PM
@@ -1258,86 +1234,43 @@ static int gk20a_pm_suspend(struct device *dev)
return -EBUSY;
#endif
ret = gk20a_pm_prepare_poweroff(dev);
if (!g->power_on)
return 0;
ret = gk20a_pm_runtime_suspend(dev);
if (ret)
return ret;
if (platform->suspend)
platform->suspend(dev);
g->suspended = true;
return 0;
}
static int gk20a_pm_resume(struct device *dev)
{
return gk20a_pm_finalize_poweron(dev);
}
struct gk20a *g = get_gk20a(dev);
int ret = 0;
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
static int gk20a_pm_initialise_domain(struct device *dev)
{
struct gk20a_platform *platform = dev_get_drvdata(dev);
struct dev_power_governor *pm_domain_gov = NULL;
struct generic_pm_domain *domain = dev_to_genpd(dev);
if (IS_ERR(domain))
if (!g->suspended)
return 0;
#ifdef CONFIG_PM
if (!platform->can_railgate)
pm_domain_gov = &pm_domain_always_on_gov;
#endif
domain->gov = pm_domain_gov;
ret = gk20a_pm_runtime_resume(dev);
if (platform->railgate_delay)
pm_genpd_set_poweroff_delay(domain, platform->railgate_delay);
device_set_wakeup_capable(dev, 0);
return 0;
}
#else
static int gk20a_pm_initialise_domain(struct device *dev)
{
struct gk20a_platform *platform = dev_get_drvdata(dev);
struct dev_power_governor *pm_domain_gov = NULL;
struct generic_pm_domain *domain = NULL;
int ret = 0;
struct gk20a_domain_data *gpu_gpd_data = (struct gk20a_domain_data *)
kzalloc(sizeof(struct gk20a_domain_data), GFP_KERNEL);
if (!gpu_gpd_data)
return -ENOMEM;
gpu_gpd_data->gk20a = platform->g;
domain = &gpu_gpd_data->gpd;
domain->name = "gpu";
#ifdef CONFIG_PM
if (!platform->can_railgate)
pm_domain_gov = &pm_domain_always_on_gov;
#endif
pm_genpd_init(domain, pm_domain_gov, true);
domain->power_off = gk20a_pm_railgate;
domain->power_on = gk20a_pm_unrailgate;
domain->dev_ops.start = gk20a_pm_enable_clk;
domain->dev_ops.stop = gk20a_pm_disable_clk;
domain->dev_ops.save_state = gk20a_pm_prepare_poweroff;
domain->dev_ops.restore_state = gk20a_pm_finalize_poweron;
domain->dev_ops.suspend = gk20a_pm_suspend;
domain->dev_ops.resume = gk20a_pm_resume;
device_set_wakeup_capable(dev, 0);
ret = pm_genpd_add_device(domain, dev);
if (platform->railgate_delay)
pm_genpd_set_poweroff_delay(domain, platform->railgate_delay);
g->suspended = false;
return ret;
}
#ifdef CONFIG_PM
static const struct dev_pm_ops gk20a_pm_ops = {
.runtime_resume = gk20a_pm_runtime_resume,
.runtime_suspend = gk20a_pm_runtime_suspend,
.resume = gk20a_pm_resume,
.suspend = gk20a_pm_suspend,
};
#endif
int gk20a_pm_init(struct device *dev)
@@ -1350,24 +1283,20 @@ int gk20a_pm_init(struct device *dev)
/* Initialise pm runtime */
if (platform->railgate_delay) {
pm_runtime_set_autosuspend_delay(dev,
platform->railgate_delay);
platform->railgate_delay);
pm_runtime_use_autosuspend(dev);
}
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev))
gk20a_pm_enable_clk(dev);
/* Enable runtime railgating if possible. If not,
* turn on the rail now. */
if (platform->can_railgate && IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
_gk20a_pm_railgate(dev);
else if (!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
_gk20a_pm_unrailgate(dev);
/* genpd will take care of runtime power management if it is enabled */
if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
err = gk20a_pm_initialise_domain(dev);
if (platform->can_railgate) {
pm_runtime_enable(dev);
if (!pm_runtime_enabled(dev))
gk20a_pm_unrailgate(dev);
else
gk20a_pm_railgate(dev);
} else {
__pm_runtime_disable(dev, false);
gk20a_pm_unrailgate(dev);
}
return err;
}
@@ -1386,24 +1315,12 @@ static int gk20a_secure_page_alloc(struct platform_device *pdev)
return err;
}
static struct of_device_id tegra_gpu_domain_match[] = {
{.compatible = "nvidia,tegra124-gpu-pd"},
{.compatible = "nvidia,tegra132-gpu-pd"},
{.compatible = "nvidia,tegra210-gpu-pd"},
{.compatible = "nvidia,tegra186-gpu-pd"},
{},
};
static int gk20a_probe(struct platform_device *dev)
{
struct gk20a *gk20a;
int err;
struct gk20a_platform *platform = NULL;
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
struct gk20a_domain_data *gk20a_domain;
#endif
if (dev->dev.of_node) {
const struct of_device_id *match;
@@ -1434,12 +1351,6 @@ static int gk20a_probe(struct platform_device *dev)
init_waitqueue_head(&gk20a->sw_irq_stall_last_handled_wq);
init_waitqueue_head(&gk20a->sw_irq_nonstall_last_handled_wq);
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
gk20a_domain = container_of(dev_to_genpd(&dev->dev),
struct gk20a_domain_data, gpd);
gk20a_domain->gk20a = gk20a;
#endif
set_gk20a(dev, gk20a);
gk20a->dev = &dev->dev;
@@ -1636,7 +1547,6 @@ static int __exit gk20a_remove(struct platform_device *pdev)
struct device *dev = &pdev->dev;
struct gk20a *g = get_gk20a(dev);
struct gk20a_platform *platform = gk20a_get_platform(dev);
struct gk20a_domain_data *gk20a_gpd;
gk20a_dbg_fn("");
@@ -1665,14 +1575,8 @@ static int __exit gk20a_remove(struct platform_device *pdev)
platform->secure_buffer.destroy(dev,
&platform->secure_buffer);
gk20a_gpd = container_of(&g, struct gk20a_domain_data, gk20a);
gk20a_gpd->gk20a = NULL;
kfree(gk20a_gpd);
if (pm_runtime_enabled(dev))
pm_runtime_disable(dev);
else
gk20a_pm_disable_clk(dev);
if (platform->remove)
platform->remove(dev);
@@ -1704,63 +1608,6 @@ static struct platform_driver gk20a_driver = {
}
};
#ifdef CONFIG_PM_GENERIC_DOMAINS_OF
static int _gk20a_init_domain(struct device_node *np,
struct generic_pm_domain *gpd)
{
bool is_off = false;
gpd->name = (char *)np->name;
if (of_property_read_bool(np, "is_off"))
is_off = true;
pm_genpd_init(gpd, NULL, is_off);
gpd->power_on = gk20a_pm_unrailgate;
gpd->power_off = gk20a_pm_railgate;
gpd->dev_ops.start = gk20a_pm_enable_clk;
gpd->dev_ops.stop = gk20a_pm_disable_clk;
gpd->dev_ops.save_state = gk20a_pm_prepare_poweroff;
gpd->dev_ops.restore_state = gk20a_pm_finalize_poweron;
gpd->dev_ops.suspend = gk20a_pm_suspend;
gpd->dev_ops.resume = gk20a_pm_resume;
of_genpd_add_provider_simple(np, gpd);
gpd->of_node = of_node_get(np);
genpd_pm_subdomain_attach(gpd);
return 0;
}
static int gk20a_domain_init(struct of_device_id *matches)
{
int ret = 0;
struct device_node *np;
struct gk20a_domain_data *gk20a_domain;
np = of_find_matching_node(NULL, matches);
if (!np)
return -ENOENT;
gk20a_domain = (struct gk20a_domain_data *)kzalloc
(sizeof(struct gk20a_domain_data), GFP_KERNEL);
if (!gk20a_domain)
return -ENOMEM;
ret = _gk20a_init_domain(np, &gk20a_domain->gpd);
return ret;
}
#else
static int gk20a_domain_init(struct of_device_id *matches)
{
return 0;
}
#endif
struct class nvgpu_class = {
.owner = THIS_MODULE,
.name = CLASS_NAME,
@@ -1775,10 +1622,6 @@ static int __init gk20a_init(void)
if (ret)
return ret;
ret = gk20a_domain_init(tegra_gpu_domain_match);
if (ret)
return ret;
ret = nvgpu_pci_init();
if (ret)
return ret;
@@ -1802,38 +1645,37 @@ int gk20a_busy(struct device *dev)
{
int ret = 0;
struct gk20a *g = get_gk20a(dev);
#ifdef CONFIG_PM
struct gk20a_platform *platform = gk20a_get_platform(dev);
#endif
down_read(&g->busy_lock);
#ifdef CONFIG_PM
if (platform->busy) {
ret = platform->busy(dev);
if (pm_runtime_enabled(dev)) {
if (platform->busy) {
ret = platform->busy(dev);
if (ret < 0) {
dev_err(dev, "%s: failed to poweron platform dependency\n",
__func__);
goto fail;
}
}
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "%s: failed to poweron platform dependency\n",
__func__);
pm_runtime_put_noidle(dev);
if (platform->idle)
platform->idle(dev);
goto fail;
}
} else {
if (!g->power_on) {
ret = gk20a_gpu_is_virtual(dev) ?
vgpu_pm_finalize_poweron(dev)
: gk20a_pm_finalize_poweron(dev);
if (ret)
goto fail;
}
}
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
pm_runtime_put_noidle(dev);
if (platform->idle)
platform->idle(dev);
goto fail;
}
#else
if (!g->power_on) {
ret = gk20a_gpu_is_virtual(dev) ?
vgpu_pm_finalize_poweron(dev)
: gk20a_pm_finalize_poweron(dev);
if (ret)
goto fail;
}
#endif
gk20a_scale_notify_busy(dev);
fail:
@@ -1844,18 +1686,22 @@ fail:
void gk20a_idle(struct device *dev)
{
#ifdef CONFIG_PM
struct gk20a_platform *platform = gk20a_get_platform(dev);
if (atomic_read(&dev->power.usage_count) == 1)
gk20a_scale_notify_idle(dev);
pm_runtime_mark_last_busy(dev);
pm_runtime_put_sync_autosuspend(dev);
if (platform->idle)
platform->idle(dev);
#else
gk20a_scale_notify_idle(dev);
if (pm_runtime_enabled(dev)) {
#ifdef CONFIG_PM
if (atomic_read(&dev->power.usage_count) == 1)
gk20a_scale_notify_idle(dev);
#endif
pm_runtime_mark_last_busy(dev);
pm_runtime_put_sync_autosuspend(dev);
if (platform->idle)
platform->idle(dev);
} else {
gk20a_scale_notify_idle(dev);
}
}
void gk20a_disable(struct gk20a *g, u32 units)
@@ -1991,8 +1837,6 @@ int __gk20a_do_idle(struct device *dev, bool force_reset)
/* Save the GPU state */
gk20a_pm_prepare_poweroff(dev);
gk20a_pm_disable_clk(dev);
/* railgate GPU */
platform->railgate(dev);
@@ -2044,8 +1888,6 @@ int __gk20a_do_unidle(struct device *dev)
*/
platform->unrailgate(dev);
gk20a_pm_enable_clk(dev);
/* restore the GPU state */
gk20a_pm_finalize_poweron(dev);

View File

@@ -664,6 +664,7 @@ struct gk20a {
struct device *dev;
struct platform_device *host1x_dev;
struct resource *reg_mem;
void __iomem *regs;
void __iomem *regs_saved;
@@ -673,6 +674,7 @@ struct gk20a {
void __iomem *bar1_saved;
bool power_on;
bool suspended;
struct rw_semaphore busy_lock;
@@ -882,11 +884,6 @@ struct gk20a_cyclestate_buffer_elem {
u64 data;
};
struct gk20a_domain_data {
struct generic_pm_domain gpd;
struct gk20a *gk20a;
};
/* debug accessories */
#ifdef CONFIG_DEBUG_FS

View File

@@ -276,49 +276,33 @@ static DEVICE_ATTR(ptimer_src_freq,
NULL);
#if defined(CONFIG_PM) && defined(CONFIG_PM_GENERIC_DOMAINS)
#if defined(CONFIG_PM)
static ssize_t railgate_enable_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct gk20a_platform *platform = dev_get_drvdata(dev);
struct generic_pm_domain *genpd = dev_to_genpd(dev);
struct gk20a *g = get_gk20a(dev);
unsigned long railgate_enable = 0;
int err = 0;
if (kstrtoul(buf, 10, &railgate_enable) < 0)
return -EINVAL;
if (railgate_enable && !platform->can_railgate) {
mutex_lock(&platform->railgate_lock);
/* release extra ref count */
gk20a_idle(dev);
platform->can_railgate = true;
genpd->gov = NULL;
pm_genpd_set_poweroff_delay(genpd, platform->railgate_delay);
/* release extra ref count:if power domains not enabled */
if ((platform->railgate) && \
!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
err = platform->railgate(dev);
mutex_unlock(&platform->railgate_lock);
} else if (railgate_enable == 0 && platform->can_railgate) {
mutex_lock(&platform->railgate_lock);
/* take extra ref count */
err = gk20a_busy(dev);
if (err)
return err;
platform->can_railgate = false;
genpd->gov = &pm_domain_always_on_gov;
pm_genpd_set_poweroff_delay(genpd, platform->railgate_delay);
/* take extra ref count - incase of power domains not enabled */
if ((platform->unrailgate) && \
!IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
err = platform->unrailgate(dev);
mutex_unlock(&platform->railgate_lock);
}
if (err)
return err;
dev_info(dev, "railgate is %s.\n", platform->can_railgate ?
"enabled" : "disabled");
/* wake-up system to make railgating_enable effective immediately */
err = gk20a_busy(g->dev);
if (err)
return err;
gk20a_idle(g->dev);
return count;
}
@@ -351,11 +335,11 @@ static ssize_t railgate_delay_store(struct device *dev,
ret = sscanf(buf, "%d", &railgate_delay);
if (ret == 1 && railgate_delay >= 0) {
struct generic_pm_domain *genpd = pd_to_genpd(dev->pm_domain);
platform->railgate_delay = railgate_delay;
pm_genpd_set_poweroff_delay(genpd, platform->railgate_delay);
pm_runtime_set_autosuspend_delay(dev, platform->railgate_delay);
} else
dev_err(dev, "Invalid powergate delay\n");
/* wake-up system to make rail-gating delay effective immediately */
err = gk20a_busy(g->dev);
if (err)
@@ -782,9 +766,7 @@ void gk20a_remove_sysfs(struct device *dev)
device_remove_file(dev, &dev_attr_is_railgated);
#ifdef CONFIG_PM
device_remove_file(dev, &dev_attr_force_idle);
#if defined(CONFIG_PM_GENERIC_DOMAINS)
device_remove_file(dev, &dev_attr_railgate_enable);
#endif
#endif
device_remove_file(dev, &dev_attr_aelpg_param);
device_remove_file(dev, &dev_attr_aelpg_enable);
@@ -823,9 +805,7 @@ void gk20a_create_sysfs(struct device *dev)
error |= device_create_file(dev, &dev_attr_is_railgated);
#ifdef CONFIG_PM
error |= device_create_file(dev, &dev_attr_force_idle);
#if defined(CONFIG_PM_GENERIC_DOMAINS)
error |= device_create_file(dev, &dev_attr_railgate_enable);
#endif
#endif
error |= device_create_file(dev, &dev_attr_aelpg_param);
error |= device_create_file(dev, &dev_attr_aelpg_enable);

View File

@@ -17,7 +17,6 @@
#define _GK20A_PLATFORM_H_
#include <linux/device.h>
#include <linux/pm_domain.h>
#include <linux/dma-attrs.h>
struct gk20a;

View File

@@ -22,7 +22,6 @@
#include <uapi/linux/nvgpu.h>
#include <linux/dma-buf.h>
#include <linux/nvmap.h>
#include <linux/tegra_pm_domains.h>
#include <linux/tegra_soctherm.h>
#include <linux/platform/tegra/clock.h>
#include <linux/platform/tegra/dvfs.h>
@@ -780,9 +779,6 @@ static int gk20a_tegra_probe(struct device *dev)
static int gk20a_tegra_late_probe(struct device *dev)
{
/* Make gk20a power domain a subdomain of host1x */
nvhost_register_client_domain(dev_to_genpd(dev));
/* Initialise tegra specific scaling quirks */
gk20a_tegra_scale_init(dev);
@@ -791,9 +787,6 @@ static int gk20a_tegra_late_probe(struct device *dev)
static int gk20a_tegra_remove(struct device *dev)
{
/* remove gk20a power subdomain from host1x */
nvhost_unregister_client_domain(dev_to_genpd(dev));
/* deinitialise tegra specific scaling quirks */
gk20a_tegra_scale_exit(dev);

View File

@@ -430,48 +430,13 @@ done:
return err;
}
static int vgpu_pm_initialise_domain(struct device *dev)
{
struct gk20a_platform *platform = dev_get_drvdata(dev);
struct dev_power_governor *pm_domain_gov = NULL;
struct gk20a_domain_data *vgpu_pd_data;
struct generic_pm_domain *domain;
vgpu_pd_data = (struct gk20a_domain_data *)kzalloc
(sizeof(struct gk20a_domain_data), GFP_KERNEL);
if (!vgpu_pd_data)
return -ENOMEM;
domain = &vgpu_pd_data->gpd;
vgpu_pd_data->gk20a = platform->g;
domain->name = "gpu";
#ifdef CONFIG_PM
pm_domain_gov = &pm_domain_always_on_gov;
#endif
pm_genpd_init(domain, pm_domain_gov, true);
domain->dev_ops.save_state = vgpu_pm_prepare_poweroff;
domain->dev_ops.restore_state = vgpu_pm_finalize_poweron;
device_set_wakeup_capable(dev, 0);
return pm_genpd_add_device(domain, dev);
}
static int vgpu_pm_init(struct device *dev)
{
int err = 0;
gk20a_dbg_fn("");
pm_runtime_enable(dev);
/* genpd will take care of runtime power management if it is enabled */
if (IS_ENABLED(CONFIG_PM_GENERIC_DOMAINS))
err = vgpu_pm_initialise_domain(dev);
__pm_runtime_disable(dev, false);
return err;
}
@@ -567,16 +532,11 @@ int vgpu_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct gk20a *g = get_gk20a(dev);
struct gk20a_domain_data *vgpu_gpd;
gk20a_dbg_fn("");
if (g->remove_support)
g->remove_support(dev);
vgpu_gpd = container_of(&g, struct gk20a_domain_data, gk20a);
vgpu_gpd->gk20a = NULL;
kfree(vgpu_gpd);
vgpu_comm_deinit();
gk20a_user_deinit(dev, &nvgpu_class);
gk20a_get_platform(dev)->g = NULL;