mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-25 11:04:51 +03:00
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:
committed by
Terje Bergstrom
parent
8417698b51
commit
e27c72446b
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#define _GK20A_PLATFORM_H_
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/pm_domain.h>
|
||||
#include <linux/dma-attrs.h>
|
||||
|
||||
struct gk20a;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user