Commit 31f18230 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge branch 'pm-domains' into pm-qos

parents 20f97caf 704d2ce6
...@@ -120,18 +120,12 @@ static int rmobile_pd_power_up(struct generic_pm_domain *genpd) ...@@ -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); 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) static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
{ {
struct generic_pm_domain *genpd = &rmobile_pd->genpd; struct generic_pm_domain *genpd = &rmobile_pd->genpd;
struct dev_power_governor *gov = rmobile_pd->gov; struct dev_power_governor *gov = rmobile_pd->gov;
genpd->flags |= GENPD_FLAG_PM_CLK; genpd->flags |= GENPD_FLAG_PM_CLK | GENPD_FLAG_ACTIVE_WAKEUP;
genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup;
genpd->power_off = rmobile_pd_power_down; genpd->power_off = rmobile_pd_power_down;
genpd->power_on = rmobile_pd_power_up; genpd->power_on = rmobile_pd_power_up;
genpd->attach_dev = cpg_mstp_attach_dev; genpd->attach_dev = cpg_mstp_attach_dev;
......
This diff is collapsed.
...@@ -14,22 +14,33 @@ ...@@ -14,22 +14,33 @@
static int dev_update_qos_constraint(struct device *dev, void *data) static int dev_update_qos_constraint(struct device *dev, void *data)
{ {
s64 *constraint_ns_p = 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; constraint_ns = dev_gpd_data(dev)->td.effective_constraint_ns;
} else {
if (constraint_ns < 0) { /*
* 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); constraint_ns = dev_pm_qos_read_value(dev);
if (constraint_ns > 0)
constraint_ns *= NSEC_PER_USEC; constraint_ns *= NSEC_PER_USEC;
} }
/* 0 means "no constraint" */
if (constraint_ns == 0) if (constraint_ns == 0)
return 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) if (constraint_ns < *constraint_ns_p || *constraint_ns_p == 0)
*constraint_ns_p = constraint_ns; *constraint_ns_p = constraint_ns;
...@@ -76,14 +87,32 @@ static bool default_suspend_ok(struct device *dev) ...@@ -76,14 +87,32 @@ static bool default_suspend_ok(struct device *dev)
device_for_each_child(dev, &constraint_ns, device_for_each_child(dev, &constraint_ns,
dev_update_qos_constraint); 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 + constraint_ns -= td->suspend_latency_ns +
td->resume_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; return false;
}
td->effective_constraint_ns = constraint_ns; 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 * 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, ...@@ -144,18 +173,16 @@ static bool __default_power_down_ok(struct dev_pm_domain *pd,
*/ */
td = &to_gpd_data(pdd)->td; td = &to_gpd_data(pdd)->td;
constraint_ns = td->effective_constraint_ns; constraint_ns = td->effective_constraint_ns;
/* default_suspend_ok() need not be called before us. */ /*
if (constraint_ns < 0) { * Negative values mean "no suspend at all" and this runs only
constraint_ns = dev_pm_qos_read_value(pdd->dev); * when all devices in the domain are suspended, so it must be
constraint_ns *= NSEC_PER_USEC; * 0 at least.
} *
* 0 means "no constraint"
*/
if (constraint_ns == 0) if (constraint_ns == 0)
continue; continue;
/*
* constraint_ns cannot be negative here, because the device has
* been suspended.
*/
if (constraint_ns <= off_on_time_ns) if (constraint_ns <= off_on_time_ns)
return false; return false;
......
...@@ -361,17 +361,6 @@ static int scpsys_power_off(struct generic_pm_domain *genpd) ...@@ -361,17 +361,6 @@ static int scpsys_power_off(struct generic_pm_domain *genpd)
return ret; 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) static void init_clks(struct platform_device *pdev, struct clk **clk)
{ {
int i; int i;
...@@ -466,7 +455,8 @@ static struct scp *init_scp(struct platform_device *pdev, ...@@ -466,7 +455,8 @@ static struct scp *init_scp(struct platform_device *pdev,
genpd->name = data->name; genpd->name = data->name;
genpd->power_off = scpsys_power_off; genpd->power_off = scpsys_power_off;
genpd->power_on = scpsys_power_on; 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; return scp;
......
...@@ -358,17 +358,6 @@ static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd, ...@@ -358,17 +358,6 @@ static void rockchip_pd_detach_dev(struct generic_pm_domain *genpd,
pm_clk_destroy(dev); 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, static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
struct device_node *node) struct device_node *node)
{ {
...@@ -489,8 +478,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu, ...@@ -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.power_on = rockchip_pd_power_on;
pd->genpd.attach_dev = rockchip_pd_attach_dev; pd->genpd.attach_dev = rockchip_pd_attach_dev;
pd->genpd.detach_dev = rockchip_pd_detach_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; 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); pm_genpd_init(&pd->genpd, NULL, false);
pmu->genpd_data.domains[id] = &pd->genpd; pmu->genpd_data.domains[id] = &pd->genpd;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#define GENPD_FLAG_PM_CLK (1U << 0) /* PM domain uses PM clk */ #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_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_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 { enum gpd_status {
GPD_STATE_ACTIVE = 0, /* PM domain is active */ GPD_STATE_ACTIVE = 0, /* PM domain is active */
...@@ -35,7 +36,6 @@ struct dev_power_governor { ...@@ -35,7 +36,6 @@ struct dev_power_governor {
struct gpd_dev_ops { struct gpd_dev_ops {
int (*start)(struct device *dev); int (*start)(struct device *dev);
int (*stop)(struct device *dev); int (*stop)(struct device *dev);
bool (*active_wakeup)(struct device *dev);
}; };
struct genpd_power_state { struct genpd_power_state {
...@@ -64,8 +64,11 @@ struct generic_pm_domain { ...@@ -64,8 +64,11 @@ struct generic_pm_domain {
unsigned int device_count; /* Number of devices */ unsigned int device_count; /* Number of devices */
unsigned int suspended_count; /* System suspend device counter */ unsigned int suspended_count; /* System suspend device counter */
unsigned int prepared_count; /* Suspend counter of prepared devices */ 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_off)(struct generic_pm_domain *domain);
int (*power_on)(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; struct gpd_dev_ops dev_ops;
s64 max_off_time_ns; /* Maximum allowed "suspended" time. */ s64 max_off_time_ns; /* Maximum allowed "suspended" time. */
bool max_off_time_changed; bool max_off_time_changed;
...@@ -121,6 +124,7 @@ struct generic_pm_domain_data { ...@@ -121,6 +124,7 @@ struct generic_pm_domain_data {
struct pm_domain_data base; struct pm_domain_data base;
struct gpd_timing_data td; struct gpd_timing_data td;
struct notifier_block nb; struct notifier_block nb;
unsigned int performance_state;
void *data; void *data;
}; };
...@@ -148,6 +152,8 @@ extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, ...@@ -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, extern int pm_genpd_init(struct generic_pm_domain *genpd,
struct dev_power_governor *gov, bool is_off); struct dev_power_governor *gov, bool is_off);
extern int pm_genpd_remove(struct generic_pm_domain *genpd); 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 simple_qos_governor;
extern struct dev_power_governor pm_domain_always_on_gov; 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) ...@@ -188,6 +194,12 @@ static inline int pm_genpd_remove(struct generic_pm_domain *genpd)
return -ENOTSUPP; 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 simple_qos_governor (*(struct dev_power_governor *)(NULL))
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL)) #define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment