Commit 1498c503 authored by Maulik Shah's avatar Maulik Shah Committed by Bjorn Andersson

PM: domains: Store the next hrtimer wakeup in genpd

The arch timer cannot wake up the Qualcomm Technologies, Inc. (QTI) SoCs
from the deeper CPUidle states. To be able to wakeup from these deeper
states, another always-on timer needs to be programmed through the so
called CONTROL_TCS.

As the RSC is part of CPU subsystem and the corresponding APSS RSC device
is attached to the cluster PM domain (through genpd), it holds the
responsibility to program the always-on timer, before entering any of these
deeper CPUidle states.

However, programming the timer requires information about the next hrtimer
wakeup for the cluster PM domain, which is currently only known by genpd.
Therefore, let's share this data through a new genpd helper function,
dev_pm_genpd_get_next_hrtimer().
Signed-off-by: default avatarMaulik Shah <quic_mkshah@quicinc.com>
Cc: "Rafael J. Wysocki" <rafael@kernel.org>
[Ulf: Reworked the code and updated the commit message]
Signed-off-by: default avatarUlf Hansson <ulf.hansson@linaro.org>
Tested-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> # SM8450
Signed-off-by: default avatarBjorn Andersson <andersson@kernel.org>
Link: https://lore.kernel.org/r/20221018152837.619426-5-ulf.hansson@linaro.org
parent 25092e61
......@@ -494,6 +494,31 @@ void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next)
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_set_next_wakeup);
/**
* dev_pm_genpd_get_next_hrtimer - Return the next_hrtimer for the genpd
* @dev: A device that is attached to the genpd.
*
* This routine should typically be called for a device, at the point of when a
* GENPD_NOTIFY_PRE_OFF notification has been sent for it.
*
* Returns the aggregated value of the genpd's next hrtimer or KTIME_MAX if no
* valid value have been set.
*/
ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
{
struct generic_pm_domain *genpd;
genpd = dev_to_genpd_safe(dev);
if (!genpd)
return KTIME_MAX;
if (genpd->gd)
return genpd->gd->next_hrtimer;
return KTIME_MAX;
}
EXPORT_SYMBOL_GPL(dev_pm_genpd_get_next_hrtimer);
static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
{
unsigned int state_idx = genpd->state_idx;
......@@ -1994,6 +2019,7 @@ static int genpd_alloc_data(struct generic_pm_domain *genpd)
gd->max_off_time_ns = -1;
gd->max_off_time_changed = true;
gd->next_wakeup = KTIME_MAX;
gd->next_hrtimer = KTIME_MAX;
}
/* Use only one "off" state if there were no states declared */
......
......@@ -375,6 +375,9 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
if (idle_duration_ns <= 0)
return false;
/* Store the next domain_wakeup to allow consumers to use it. */
genpd->gd->next_hrtimer = domain_wakeup;
/*
* Find the deepest idle state that has its residency value satisfied
* and by also taking into account the power off latency for the state.
......
......@@ -17,6 +17,7 @@
#include <linux/notifier.h>
#include <linux/spinlock.h>
#include <linux/cpumask.h>
#include <linux/time64.h>
/*
* Flags to control the behaviour of a genpd.
......@@ -95,6 +96,7 @@ struct genpd_governor_data {
s64 max_off_time_ns;
bool max_off_time_changed;
ktime_t next_wakeup;
ktime_t next_hrtimer;
bool cached_power_down_ok;
bool cached_power_down_state_idx;
};
......@@ -232,6 +234,7 @@ int dev_pm_genpd_set_performance_state(struct device *dev, unsigned int state);
int dev_pm_genpd_add_notifier(struct device *dev, struct notifier_block *nb);
int dev_pm_genpd_remove_notifier(struct device *dev);
void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next);
ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev);
extern struct dev_power_governor simple_qos_governor;
extern struct dev_power_governor pm_domain_always_on_gov;
......@@ -293,6 +296,10 @@ static inline int dev_pm_genpd_remove_notifier(struct device *dev)
static inline void dev_pm_genpd_set_next_wakeup(struct device *dev, ktime_t next)
{ }
static inline ktime_t dev_pm_genpd_get_next_hrtimer(struct device *dev)
{
return KTIME_MAX;
}
#define simple_qos_governor (*(struct dev_power_governor *)(NULL))
#define pm_domain_always_on_gov (*(struct dev_power_governor *)(NULL))
#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