Merge branch 'pm-domains'
* pm-domains: PM / Domains: Fix genpd to deal with drivers returning 1 from ->prepare() PM / domains: Rework governor code to be more consistent PM / Domains: Remove gpd_dev_ops.active_wakeup() callback soc: rockchip: power-domain: Use GENPD_FLAG_ACTIVE_WAKEUP soc: mediatek: Use GENPD_FLAG_ACTIVE_WAKEUP ARM: shmobile: pm-rmobile: Use GENPD_FLAG_ACTIVE_WAKEUP PM / Domains: Allow genpd users to specify default active wakeup behavior PM / Domains: Add support to select performance-state of domains PM / Domains: Rename genpd internals from pm_genpd_* to genpd_*
This commit is contained in:
commit
29aaf90875
6 changed files with 226 additions and 123 deletions
|
@ -120,18 +120,12 @@ static int rmobile_pd_power_up(struct generic_pm_domain *genpd)
|
|||
return __rmobile_pd_power_up(to_rmobile_pd(genpd), true);
|
||||
}
|
||||
|
||||
static bool rmobile_pd_active_wakeup(struct device *dev)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
|
||||
{
|
||||
struct generic_pm_domain *genpd = &rmobile_pd->genpd;
|
||||
struct dev_power_governor *gov = rmobile_pd->gov;
|
||||
|
||||
genpd->flags |= GENPD_FLAG_PM_CLK;
|
||||
genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup;
|
||||
genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
|
||||
genpd->power_off = rmobile_pd_power_down;
|
||||
genpd->power_on = rmobile_pd_power_up;
|
||||
genpd->attach_dev = cpg_mstp_attach_dev;
|
||||
|
|
|
@ -124,6 +124,7 @@ static const struct genpd_lock_ops genpd_spin_ops = {
|
|||
#define genpd_status_on(genpd) (genpd->status == GPD_STATE_ACTIVE)
|
||||
#define genpd_is_irq_safe(genpd) (genpd->flags & GENPD_FLAG_IRQ_SAFE)
|
||||
#define genpd_is_always_on(genpd) (genpd->flags & GENPD_FLAG_ALWAYS_ON)
|
||||
#define genpd_is_active_wakeup(genpd) (genpd->flags & GENPD_FLAG_ACTIVE_WAKEUP)
|
||||
|
||||
static inline bool irq_safe_dev_in_no_sleep_domain(struct device *dev,
|
||||
const struct generic_pm_domain *genpd)
|
||||
|
@ -237,6 +238,95 @@ static void genpd_update_accounting(struct generic_pm_domain *genpd)
|
|||
static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* dev_pm_genpd_set_performance_state- Set performance state of device's power
|
||||
* domain.
|
||||
*
|
||||
* @dev: Device for which the performance-state needs to be set.
|
||||
* @state: Target performance state of the device. This can be set as 0 when the
|
||||
* device doesn't have any performance state constraints left (And so
|
||||
* the device wouldn't participate anymore to find the target
|
||||
* performance state of the genpd).
|
||||
*
|
||||
* It is assumed that the users guarantee that the genpd wouldn't be detached
|
||||
* while this routine is getting called.
|
||||
*
|
||||
* Returns 0 on success and negative error values on failures.
|
||||
*/
|
||||
int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
struct generic_pm_domain_data *gpd_data, *pd_data;
|
||||
struct pm_domain_data *pdd;
|
||||
unsigned int prev;
|
||||
int ret = 0;
|
||||
|
||||
genpd = dev_to_genpd(dev);
|
||||
if (IS_ERR(genpd))
|
||||
return -ENODEV;
|
||||
|
||||
if (unlikely(!genpd->set_performance_state))
|
||||
return -EINVAL;
|
||||
|
||||
if (unlikely(!dev->power.subsys_data ||
|
||||
!dev->power.subsys_data->domain_data)) {
|
||||
WARN_ON(1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
genpd_lock(genpd);
|
||||
|
||||
gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
|
||||
prev = gpd_data->performance_state;
|
||||
gpd_data->performance_state = state;
|
||||
|
||||
/* New requested state is same as Max requested state */
|
||||
if (state == genpd->performance_state)
|
||||
goto unlock;
|
||||
|
||||
/* New requested state is higher than Max requested state */
|
||||
if (state > genpd->performance_state)
|
||||
goto update_state;
|
||||
|
||||
/* Traverse all devices within the domain */
|
||||
list_for_each_entry(pdd, &genpd->dev_list, list_node) {
|
||||
pd_data = to_gpd_data(pdd);
|
||||
|
||||
if (pd_data->performance_state > state)
|
||||
state = pd_data->performance_state;
|
||||
}
|
||||
|
||||
if (state == genpd->performance_state)
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
* We aren't propagating performance state changes of a subdomain to its
|
||||
* masters as we don't have hardware that needs it. Over that, the
|
||||
* performance states of subdomain and its masters may not have
|
||||
* one-to-one mapping and would require additional information. We can
|
||||
* get back to this once we have hardware that needs it. For that
|
||||
* reason, we don't have to consider performance state of the subdomains
|
||||
* of genpd here.
|
||||
*/
|
||||
|
||||
update_state:
|
||||
if (genpd_status_on(genpd)) {
|
||||
ret = genpd->set_performance_state(genpd, state);
|
||||
if (ret) {
|
||||
gpd_data->performance_state = prev;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
genpd->performance_state = state;
|
||||
|
||||
unlock:
|
||||
genpd_unlock(genpd);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_genpd_set_performance_state);
|
||||
|
||||
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
|
||||
{
|
||||
unsigned int state_idx = genpd->state_idx;
|
||||
|
@ -256,6 +346,15 @@ static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
|
|||
return ret;
|
||||
|
||||
elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
|
||||
|
||||
if (unlikely(genpd->set_performance_state)) {
|
||||
ret = genpd->set_performance_state(genpd, genpd->performance_state);
|
||||
if (ret) {
|
||||
pr_warn("%s: Failed to set performance state %d (%d)\n",
|
||||
genpd->name, genpd->performance_state, ret);
|
||||
}
|
||||
}
|
||||
|
||||
if (elapsed_ns <= genpd->states[state_idx].power_on_latency_ns)
|
||||
return ret;
|
||||
|
||||
|
@ -749,11 +848,7 @@ late_initcall(genpd_power_off_unused);
|
|||
|
||||
#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_GENERIC_DOMAINS_OF)
|
||||
|
||||
/**
|
||||
* pm_genpd_present - Check if the given PM domain has been initialized.
|
||||
* @genpd: PM domain to check.
|
||||
*/
|
||||
static bool pm_genpd_present(const struct generic_pm_domain *genpd)
|
||||
static bool genpd_present(const struct generic_pm_domain *genpd)
|
||||
{
|
||||
const struct generic_pm_domain *gpd;
|
||||
|
||||
|
@ -771,12 +866,6 @@ static bool pm_genpd_present(const struct generic_pm_domain *genpd)
|
|||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
||||
static bool genpd_dev_active_wakeup(const struct generic_pm_domain *genpd,
|
||||
struct device *dev)
|
||||
{
|
||||
return GENPD_DEV_CALLBACK(genpd, bool, active_wakeup, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* genpd_sync_power_off - Synchronously power off a PM domain and its masters.
|
||||
* @genpd: PM domain to power off, if possible.
|
||||
|
@ -863,7 +952,7 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock,
|
|||
* @genpd: PM domain the device belongs to.
|
||||
*
|
||||
* There are two cases in which a device that can wake up the system from sleep
|
||||
* states should be resumed by pm_genpd_prepare(): (1) if the device is enabled
|
||||
* states should be resumed by genpd_prepare(): (1) if the device is enabled
|
||||
* to wake up the system and it has to remain active for this purpose while the
|
||||
* system is in the sleep state and (2) if the device is not enabled to wake up
|
||||
* the system from sleep states and it generally doesn't generate wakeup signals
|
||||
|
@ -881,12 +970,12 @@ static bool resume_needed(struct device *dev,
|
|||
if (!device_can_wakeup(dev))
|
||||
return false;
|
||||
|
||||
active_wakeup = genpd_dev_active_wakeup(genpd, dev);
|
||||
active_wakeup = genpd_is_active_wakeup(genpd);
|
||||
return device_may_wakeup(dev) ? active_wakeup : !active_wakeup;
|
||||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_prepare - Start power transition of a device in a PM domain.
|
||||
* genpd_prepare - Start power transition of a device in a PM domain.
|
||||
* @dev: Device to start the transition of.
|
||||
*
|
||||
* Start a power transition of a device (during a system-wide power transition)
|
||||
|
@ -894,7 +983,7 @@ static bool resume_needed(struct device *dev,
|
|||
* an object of type struct generic_pm_domain representing a PM domain
|
||||
* consisting of I/O devices.
|
||||
*/
|
||||
static int pm_genpd_prepare(struct device *dev)
|
||||
static int genpd_prepare(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
int ret;
|
||||
|
@ -921,7 +1010,7 @@ static int pm_genpd_prepare(struct device *dev)
|
|||
genpd_unlock(genpd);
|
||||
|
||||
ret = pm_generic_prepare(dev);
|
||||
if (ret) {
|
||||
if (ret < 0) {
|
||||
genpd_lock(genpd);
|
||||
|
||||
genpd->prepared_count--;
|
||||
|
@ -929,7 +1018,8 @@ static int pm_genpd_prepare(struct device *dev)
|
|||
genpd_unlock(genpd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
/* Never return 1, as genpd don't cope with the direct_complete path. */
|
||||
return ret >= 0 ? 0 : ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -950,7 +1040,7 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff)
|
|||
if (IS_ERR(genpd))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
|
||||
if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd))
|
||||
return 0;
|
||||
|
||||
if (poweroff)
|
||||
|
@ -975,13 +1065,13 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff)
|
|||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain.
|
||||
* genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain.
|
||||
* @dev: Device to suspend.
|
||||
*
|
||||
* Stop the device and remove power from the domain if all devices in it have
|
||||
* been stopped.
|
||||
*/
|
||||
static int pm_genpd_suspend_noirq(struct device *dev)
|
||||
static int genpd_suspend_noirq(struct device *dev)
|
||||
{
|
||||
dev_dbg(dev, "%s()\n", __func__);
|
||||
|
||||
|
@ -989,12 +1079,12 @@ static int pm_genpd_suspend_noirq(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_resume_noirq - Start of resume of device in an I/O PM domain.
|
||||
* genpd_resume_noirq - Start of resume of device in an I/O PM domain.
|
||||
* @dev: Device to resume.
|
||||
*
|
||||
* Restore power to the device's PM domain, if necessary, and start the device.
|
||||
*/
|
||||
static int pm_genpd_resume_noirq(struct device *dev)
|
||||
static int genpd_resume_noirq(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
int ret = 0;
|
||||
|
@ -1005,7 +1095,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
|
|||
if (IS_ERR(genpd))
|
||||
return -EINVAL;
|
||||
|
||||
if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
|
||||
if (dev->power.wakeup_path && genpd_is_active_wakeup(genpd))
|
||||
return 0;
|
||||
|
||||
genpd_lock(genpd);
|
||||
|
@ -1024,7 +1114,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain.
|
||||
* genpd_freeze_noirq - Completion of freezing a device in an I/O PM domain.
|
||||
* @dev: Device to freeze.
|
||||
*
|
||||
* Carry out a late freeze of a device under the assumption that its
|
||||
|
@ -1032,7 +1122,7 @@ static int pm_genpd_resume_noirq(struct device *dev)
|
|||
* struct generic_pm_domain representing a power domain consisting of I/O
|
||||
* devices.
|
||||
*/
|
||||
static int pm_genpd_freeze_noirq(struct device *dev)
|
||||
static int genpd_freeze_noirq(struct device *dev)
|
||||
{
|
||||
const struct generic_pm_domain *genpd;
|
||||
int ret = 0;
|
||||
|
@ -1054,13 +1144,13 @@ static int pm_genpd_freeze_noirq(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_thaw_noirq - Early thaw of device in an I/O PM domain.
|
||||
* genpd_thaw_noirq - Early thaw of device in an I/O PM domain.
|
||||
* @dev: Device to thaw.
|
||||
*
|
||||
* Start the device, unless power has been removed from the domain already
|
||||
* before the system transition.
|
||||
*/
|
||||
static int pm_genpd_thaw_noirq(struct device *dev)
|
||||
static int genpd_thaw_noirq(struct device *dev)
|
||||
{
|
||||
const struct generic_pm_domain *genpd;
|
||||
int ret = 0;
|
||||
|
@ -1081,14 +1171,14 @@ static int pm_genpd_thaw_noirq(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_poweroff_noirq - Completion of hibernation of device in an
|
||||
* genpd_poweroff_noirq - Completion of hibernation of device in an
|
||||
* I/O PM domain.
|
||||
* @dev: Device to poweroff.
|
||||
*
|
||||
* Stop the device and remove power from the domain if all devices in it have
|
||||
* been stopped.
|
||||
*/
|
||||
static int pm_genpd_poweroff_noirq(struct device *dev)
|
||||
static int genpd_poweroff_noirq(struct device *dev)
|
||||
{
|
||||
dev_dbg(dev, "%s()\n", __func__);
|
||||
|
||||
|
@ -1096,13 +1186,13 @@ static int pm_genpd_poweroff_noirq(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_restore_noirq - Start of restore of device in an I/O PM domain.
|
||||
* genpd_restore_noirq - Start of restore of device in an I/O PM domain.
|
||||
* @dev: Device to resume.
|
||||
*
|
||||
* Make sure the domain will be in the same power state as before the
|
||||
* hibernation the system is resuming from and start the device if necessary.
|
||||
*/
|
||||
static int pm_genpd_restore_noirq(struct device *dev)
|
||||
static int genpd_restore_noirq(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
int ret = 0;
|
||||
|
@ -1139,7 +1229,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* pm_genpd_complete - Complete power transition of a device in a power domain.
|
||||
* genpd_complete - Complete power transition of a device in a power domain.
|
||||
* @dev: Device to complete the transition of.
|
||||
*
|
||||
* Complete a power transition of a device (during a system-wide power
|
||||
|
@ -1147,7 +1237,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
|
|||
* domain member of an object of type struct generic_pm_domain representing
|
||||
* a power domain consisting of I/O devices.
|
||||
*/
|
||||
static void pm_genpd_complete(struct device *dev)
|
||||
static void genpd_complete(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
|
||||
|
@ -1180,7 +1270,7 @@ static void genpd_syscore_switch(struct device *dev, bool suspend)
|
|||
struct generic_pm_domain *genpd;
|
||||
|
||||
genpd = dev_to_genpd(dev);
|
||||
if (!pm_genpd_present(genpd))
|
||||
if (!genpd_present(genpd))
|
||||
return;
|
||||
|
||||
if (suspend) {
|
||||
|
@ -1206,14 +1296,14 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron);
|
|||
|
||||
#else /* !CONFIG_PM_SLEEP */
|
||||
|
||||
#define pm_genpd_prepare NULL
|
||||
#define pm_genpd_suspend_noirq NULL
|
||||
#define pm_genpd_resume_noirq NULL
|
||||
#define pm_genpd_freeze_noirq NULL
|
||||
#define pm_genpd_thaw_noirq NULL
|
||||
#define pm_genpd_poweroff_noirq NULL
|
||||
#define pm_genpd_restore_noirq NULL
|
||||
#define pm_genpd_complete NULL
|
||||
#define genpd_prepare NULL
|
||||
#define genpd_suspend_noirq NULL
|
||||
#define genpd_resume_noirq NULL
|
||||
#define genpd_freeze_noirq NULL
|
||||
#define genpd_thaw_noirq NULL
|
||||
#define genpd_poweroff_noirq NULL
|
||||
#define genpd_restore_noirq NULL
|
||||
#define genpd_complete NULL
|
||||
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
|
@ -1239,7 +1329,7 @@ static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
|
|||
|
||||
gpd_data->base.dev = dev;
|
||||
gpd_data->td.constraint_changed = true;
|
||||
gpd_data->td.effective_constraint_ns = -1;
|
||||
gpd_data->td.effective_constraint_ns = 0;
|
||||
gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
|
@ -1574,14 +1664,14 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
|
|||
genpd->accounting_time = ktime_get();
|
||||
genpd->domain.ops.runtime_suspend = genpd_runtime_suspend;
|
||||
genpd->domain.ops.runtime_resume = genpd_runtime_resume;
|
||||
genpd->domain.ops.prepare = pm_genpd_prepare;
|
||||
genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq;
|
||||
genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq;
|
||||
genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq;
|
||||
genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq;
|
||||
genpd->domain.ops.poweroff_noirq = pm_genpd_poweroff_noirq;
|
||||
genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
|
||||
genpd->domain.ops.complete = pm_genpd_complete;
|
||||
genpd->domain.ops.prepare = genpd_prepare;
|
||||
genpd->domain.ops.suspend_noirq = genpd_suspend_noirq;
|
||||
genpd->domain.ops.resume_noirq = genpd_resume_noirq;
|
||||
genpd->domain.ops.freeze_noirq = genpd_freeze_noirq;
|
||||
genpd->domain.ops.thaw_noirq = genpd_thaw_noirq;
|
||||
genpd->domain.ops.poweroff_noirq = genpd_poweroff_noirq;
|
||||
genpd->domain.ops.restore_noirq = genpd_restore_noirq;
|
||||
genpd->domain.ops.complete = genpd_complete;
|
||||
|
||||
if (genpd->flags & GENPD_FLAG_PM_CLK) {
|
||||
genpd->dev_ops.stop = pm_clk_suspend;
|
||||
|
@ -1795,7 +1885,7 @@ int of_genpd_add_provider_simple(struct device_node *np,
|
|||
|
||||
mutex_lock(&gpd_list_lock);
|
||||
|
||||
if (pm_genpd_present(genpd)) {
|
||||
if (genpd_present(genpd)) {
|
||||
ret = genpd_add_provider(np, genpd_xlate_simple, genpd);
|
||||
if (!ret) {
|
||||
genpd->provider = &np->fwnode;
|
||||
|
@ -1831,7 +1921,7 @@ int of_genpd_add_provider_onecell(struct device_node *np,
|
|||
for (i = 0; i < data->num_domains; i++) {
|
||||
if (!data->domains[i])
|
||||
continue;
|
||||
if (!pm_genpd_present(data->domains[i]))
|
||||
if (!genpd_present(data->domains[i]))
|
||||
goto error;
|
||||
|
||||
data->domains[i]->provider = &np->fwnode;
|
||||
|
@ -2274,7 +2364,7 @@ EXPORT_SYMBOL_GPL(of_genpd_parse_idle_states);
|
|||
#include <linux/seq_file.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kobject.h>
|
||||
static struct dentry *pm_genpd_debugfs_dir;
|
||||
static struct dentry *genpd_debugfs_dir;
|
||||
|
||||
/*
|
||||
* TODO: This function is a slightly modified version of rtpm_status_show
|
||||
|
@ -2302,7 +2392,7 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)
|
|||
seq_puts(s, p);
|
||||
}
|
||||
|
||||
static int pm_genpd_summary_one(struct seq_file *s,
|
||||
static int genpd_summary_one(struct seq_file *s,
|
||||
struct generic_pm_domain *genpd)
|
||||
{
|
||||
static const char * const status_lookup[] = {
|
||||
|
@ -2373,7 +2463,7 @@ static int genpd_summary_show(struct seq_file *s, void *data)
|
|||
return -ERESTARTSYS;
|
||||
|
||||
list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
|
||||
ret = pm_genpd_summary_one(s, genpd);
|
||||
ret = genpd_summary_one(s, genpd);
|
||||
if (ret)
|
||||
break;
|
||||
}
|
||||
|
@ -2559,23 +2649,23 @@ define_genpd_debugfs_fops(active_time);
|
|||
define_genpd_debugfs_fops(total_idle_time);
|
||||
define_genpd_debugfs_fops(devices);
|
||||
|
||||
static int __init pm_genpd_debug_init(void)
|
||||
static int __init genpd_debug_init(void)
|
||||
{
|
||||
struct dentry *d;
|
||||
struct generic_pm_domain *genpd;
|
||||
|
||||
pm_genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
|
||||
genpd_debugfs_dir = debugfs_create_dir("pm_genpd", NULL);
|
||||
|
||||
if (!pm_genpd_debugfs_dir)
|
||||
if (!genpd_debugfs_dir)
|
||||
return -ENOMEM;
|
||||
|
||||
d = debugfs_create_file("pm_genpd_summary", S_IRUGO,
|
||||
pm_genpd_debugfs_dir, NULL, &genpd_summary_fops);
|
||||
genpd_debugfs_dir, NULL, &genpd_summary_fops);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
list_for_each_entry(genpd, &gpd_list, gpd_list_node) {
|
||||
d = debugfs_create_dir(genpd->name, pm_genpd_debugfs_dir);
|
||||
d = debugfs_create_dir(genpd->name, genpd_debugfs_dir);
|
||||
if (!d)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -2595,11 +2685,11 @@ static int __init pm_genpd_debug_init(void)
|
|||
|
||||
return 0;
|
||||
}
|
||||
late_initcall(pm_genpd_debug_init);
|
||||
late_initcall(genpd_debug_init);
|
||||
|
||||
static void __exit pm_genpd_debug_exit(void)
|
||||
static void __exit genpd_debug_exit(void)
|
||||
{
|
||||
debugfs_remove_recursive(pm_genpd_debugfs_dir);
|
||||
debugfs_remove_recursive(genpd_debugfs_dir);
|
||||
}
|
||||
__exitcall(pm_genpd_debug_exit);
|
||||
__exitcall(genpd_debug_exit);
|
||||
#endif /* CONFIG_DEBUG_FS */
|
||||
|
|
|
@ -14,22 +14,33 @@
|
|||
static int dev_update_qos_constraint(struct device *dev, void *data)
|
||||
{
|
||||
s64 *constraint_ns_p = data;
|
||||
s32 constraint_ns = -1;
|
||||
s64 constraint_ns;
|
||||
|
||||
if (dev->power.subsys_data && dev->power.subsys_data->domain_data)
|
||||
if (dev->power.subsys_data && dev->power.subsys_data->domain_data) {
|
||||
/*
|
||||
* Only take suspend-time QoS constraints of devices into
|
||||
* account, because constraints updated after the device has
|
||||
* been suspended are not guaranteed to be taken into account
|
||||
* anyway. In order for them to take effect, the device has to
|
||||
* be resumed and suspended again.
|
||||
*/
|
||||
constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
|
||||
|
||||
if (constraint_ns < 0) {
|
||||
} else {
|
||||
/*
|
||||
* The child is not in a domain and there's no info on its
|
||||
* suspend/resume latencies, so assume them to be negligible and
|
||||
* take its current PM QoS constraint (that's the only thing
|
||||
* known at this point anyway).
|
||||
*/
|
||||
constraint_ns = dev_pm_qos_read_value(dev);
|
||||
if (constraint_ns > 0)
|
||||
constraint_ns *= NSEC_PER_USEC;
|
||||
}
|
||||
|
||||
/* 0 means "no constraint" */
|
||||
if (constraint_ns == 0)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* constraint_ns cannot be negative here, because the device has been
|
||||
* suspended.
|
||||
*/
|
||||
if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
|
||||
*constraint_ns_p = constraint_ns;
|
||||
|
||||
|
@ -76,14 +87,32 @@ static bool default_suspend_ok(struct device *dev)
|
|||
device_for_each_child(dev, &constraint_ns,
|
||||
dev_update_qos_constraint);
|
||||
|
||||
if (constraint_ns > 0) {
|
||||
if (constraint_ns == 0) {
|
||||
/* "No restriction", so the device is allowed to suspend. */
|
||||
td->effective_constraint_ns = 0;
|
||||
td->cached_suspend_ok = true;
|
||||
} else if (constraint_ns < 0) {
|
||||
/*
|
||||
* This triggers if one of the children that don't belong to a
|
||||
* domain has a negative PM QoS constraint and it's better not
|
||||
* to suspend then. effective_constraint_ns is negative already
|
||||
* and cached_suspend_ok is false, so bail out.
|
||||
*/
|
||||
return false;
|
||||
} else {
|
||||
constraint_ns -= td->suspend_latency_ns +
|
||||
td->resume_latency_ns;
|
||||
if (constraint_ns == 0)
|
||||
/*
|
||||
* effective_constraint_ns is negative already and
|
||||
* cached_suspend_ok is false, so if the computed value is not
|
||||
* positive, return right away.
|
||||
*/
|
||||
if (constraint_ns <= 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
td->effective_constraint_ns = constraint_ns;
|
||||
td->cached_suspend_ok = constraint_ns >= 0;
|
||||
td->cached_suspend_ok = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* The children have been suspended already, so we don't need to take
|
||||
|
@ -144,18 +173,16 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
|
|||
*/
|
||||
td = &to_gpd_data(pdd)->td;
|
||||
constraint_ns = td->effective_constraint_ns;
|
||||
/* default_suspend_ok() need not be called before us. */
|
||||
if (constraint_ns < 0) {
|
||||
constraint_ns = dev_pm_qos_read_value(pdd->dev);
|
||||
constraint_ns *= NSEC_PER_USEC;
|
||||
}
|
||||
/*
|
||||
* Negative values mean "no suspend at all" and this runs only
|
||||
* when all devices in the domain are suspended, so it must be
|
||||
* 0 at least.
|
||||
*
|
||||
* 0 means "no constraint"
|
||||
*/
|
||||
if (constraint_ns == 0)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* constraint_ns cannot be negative here, because the device has
|
||||
* been suspended.
|
||||
*/
|
||||
if (constraint_ns <= off_on_time_ns)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -361,17 +361,6 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool scpsys_active_wakeup(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
struct scp_domain *scpd;
|
||||
|
||||
genpd = pd_to_genpd(dev->pm_domain);
|
||||
scpd = container_of(genpd, struct scp_domain, genpd);
|
||||
|
||||
return scpd->data->active_wakeup;
|
||||
}
|
||||
|
||||
static void init_clks(struct platform_device *pdev, struct clk **clk)
|
||||
{
|
||||
int i;
|
||||
|
@ -466,7 +455,8 @@ static struct scp *init_scp(struct platform_device *pdev,
|
|||
genpd->name = data->name;
|
||||
genpd->power_off = scpsys_power_off;
|
||||
genpd->power_on = scpsys_power_on;
|
||||
genpd->dev_ops.active_wakeup = scpsys_active_wakeup;
|
||||
if (scpd->data->active_wakeup)
|
||||
genpd->flags |= GENPD_FLAG_ACTIVE_WAKEUP;
|
||||
}
|
||||
|
||||
return scp;
|
||||
|
|
|
@ -358,17 +358,6 @@ static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
|
|||
pm_clk_destroy(dev);
|
||||
}
|
||||
|
||||
static bool rockchip_active_wakeup(struct device *dev)
|
||||
{
|
||||
struct generic_pm_domain *genpd;
|
||||
struct rockchip_pm_domain *pd;
|
||||
|
||||
genpd = pd_to_genpd(dev->pm_domain);
|
||||
pd = container_of(genpd, struct rockchip_pm_domain, genpd);
|
||||
|
||||
return pd->info->active_wakeup;
|
||||
}
|
||||
|
||||
static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
||||
struct device_node *node)
|
||||
{
|
||||
|
@ -489,8 +478,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
|
|||
pd->genpd.power_on = rockchip_pd_power_on;
|
||||
pd->genpd.attach_dev = rockchip_pd_attach_dev;
|
||||
pd->genpd.detach_dev = rockchip_pd_detach_dev;
|
||||
pd->genpd.dev_ops.active_wakeup = rockchip_active_wakeup;
|
||||
pd->genpd.flags = GENPD_FLAG_PM_CLK;
|
||||
if (pd_info->active_wakeup)
|
||||
pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
|
||||
pm_genpd_init(&pd->genpd, NULL, false);
|
||||
|
||||
pmu->genpd_data.domains[id] = &pd->genpd;
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#define GENPD_FLAG_PM_CLK (1U << 0) /* PM domain uses PM clk */
|
||||
#define GENPD_FLAG_IRQ_SAFE (1U << 1) /* PM domain operates in atomic */
|
||||
#define GENPD_FLAG_ALWAYS_ON (1U << 2) /* PM domain is always powered on */
|
||||
#define GENPD_FLAG_ACTIVE_WAKEUP (1U << 3) /* Keep devices active if wakeup */
|
||||
|
||||
enum gpd_status {
|
||||
GPD_STATE_ACTIVE = 0, /* PM domain is active */
|
||||
|
@ -35,7 +36,6 @@ struct dev_power_governor {
|
|||
struct gpd_dev_ops {
|
||||
int (*start)(struct device *dev);
|
||||
int (*stop)(struct device *dev);
|
||||
bool (*active_wakeup)(struct device *dev);
|
||||
};
|
||||
|
||||
struct genpd_power_state {
|
||||
|
@ -64,8 +64,11 @@ struct generic_pm_domain {
|
|||
unsigned int device_count; /* Number of devices */
|
||||
unsigned int suspended_count; /* System suspend device counter */
|
||||
unsigned int prepared_count; /* Suspend counter of prepared devices */
|
||||
unsigned int performance_state; /* Aggregated max performance state */
|
||||
int (*power_off)(struct generic_pm_domain *domain);
|
||||
int (*power_on)(struct generic_pm_domain *domain);
|
||||
int (*set_performance_state)(struct generic_pm_domain *genpd,
|
||||
unsigned int state);
|
||||
struct gpd_dev_ops dev_ops;
|
||||
s64 max_off_time_ns; /* Maximum allowed "suspended" time. */
|
||||
bool max_off_time_changed;
|
||||
|
@ -121,6 +124,7 @@ struct generic_pm_domain_data {
|
|||
struct pm_domain_data base;
|
||||
struct gpd_timing_data td;
|
||||
struct notifier_block nb;
|
||||
unsigned int performance_state;
|
||||
void *data;
|
||||
};
|
||||
|
||||
|
@ -148,6 +152,8 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
|
|||
extern int pm_genpd_init(struct generic_pm_domain *genpd,
|
||||
struct dev_power_governor *gov, bool is_off);
|
||||
extern int pm_genpd_remove(struct generic_pm_domain *genpd);
|
||||
extern int dev_pm_genpd_set_performance_state(struct device *dev,
|
||||
unsigned int state);
|
||||
|
||||
extern struct dev_power_governor simple_qos_governor;
|
||||
extern struct dev_power_governor pm_domain_always_on_gov;
|
||||
|
@ -188,6 +194,12 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
|
|||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
static inline int dev_pm_genpd_set_performance_state(struct device *dev,
|
||||
unsigned int state)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
#define simple_qos_governor (*(struct dev_power_governor *)(NULL))
|
||||
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue