Message ID | 20191211154343.29765-13-ulf.hansson@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | cpuidle: psci: Support hierarchical CPU arrangement | expand |
On Thu, 19 Dec 2019 at 15:33, Sudeep Holla <sudeep.holla@arm.com> wrote: > > On Wed, Dec 11, 2019 at 04:43:41PM +0100, Ulf Hansson wrote: > > When the hierarchical CPU topology is used and when a CPU is put offline, > > that CPU prevents its PM domain from being powered off, which is because > > genpd observes the corresponding attached device as being active from a > > runtime PM point of view. Furthermore, any potential master PM domains are > > also prevented from being powered off. > > > > To address this limitation, let's add add a new CPU hotplug state > > (CPUHP_AP_CPU_PM_STARTING) and register up/down callbacks for it, which > > allows us to deal with runtime PM accordingly. > > > > Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> > > --- > > > > Changes in v4: > > - Folded in the patch to be part of the series. > > - Rebased on top of earlier changes. > > > > --- > > drivers/cpuidle/cpuidle-psci.c | 45 +++++++++++++++++++++++++++++++++- > > include/linux/cpuhotplug.h | 1 + > > 2 files changed, 45 insertions(+), 1 deletion(-) > > > > diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c > > index 6e7804e697ed..34a89d99bb0f 100644 > > --- a/drivers/cpuidle/cpuidle-psci.c > > +++ b/drivers/cpuidle/cpuidle-psci.c > > @@ -8,6 +8,7 @@ > > > > #define pr_fmt(fmt) "CPUidle PSCI: " fmt > > > > +#include <linux/cpuhotplug.h> > > #include <linux/cpuidle.h> > > #include <linux/cpumask.h> > > #include <linux/cpu_pm.h> > > @@ -31,6 +32,7 @@ struct psci_cpuidle_data { > > > > static DEFINE_PER_CPU_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_data); > > static DEFINE_PER_CPU(u32, domain_state); > > +static bool psci_cpuidle_use_cpuhp; > > > > [...] > > > + > > +static void psci_idle_init_cpuhp(void) > > +{ > > Can this be made __init along with the boolean psci_cpuidle_use_cpuhp ? Yeah, make sense! > > With that, > Reviewed-by: Sudeep Holla <sudeep.holla@arm.com> Thanks! Kind regards Uffe
diff --git a/drivers/cpuidle/cpuidle-psci.c b/drivers/cpuidle/cpuidle-psci.c index 6e7804e697ed..34a89d99bb0f 100644 --- a/drivers/cpuidle/cpuidle-psci.c +++ b/drivers/cpuidle/cpuidle-psci.c @@ -8,6 +8,7 @@ #define pr_fmt(fmt) "CPUidle PSCI: " fmt +#include <linux/cpuhotplug.h> #include <linux/cpuidle.h> #include <linux/cpumask.h> #include <linux/cpu_pm.h> @@ -31,6 +32,7 @@ struct psci_cpuidle_data { static DEFINE_PER_CPU_READ_MOSTLY(struct psci_cpuidle_data, psci_cpuidle_data); static DEFINE_PER_CPU(u32, domain_state); +static bool psci_cpuidle_use_cpuhp; static inline void psci_set_domain_state(u32 state) { @@ -72,6 +74,44 @@ static int psci_enter_domain_idle_state(struct cpuidle_device *dev, return ret; } +static int psci_idle_cpuhp_up(unsigned int cpu) +{ + struct device *pd_dev = __this_cpu_read(psci_cpuidle_data.dev); + + if (pd_dev) + pm_runtime_get_sync(pd_dev); + + return 0; +} + +static int psci_idle_cpuhp_down(unsigned int cpu) +{ + struct device *pd_dev = __this_cpu_read(psci_cpuidle_data.dev); + + if (pd_dev) { + pm_runtime_put_sync(pd_dev); + /* Clear domain state to start fresh at next online. */ + psci_set_domain_state(0); + } + + return 0; +} + +static void psci_idle_init_cpuhp(void) +{ + int err; + + if (!psci_cpuidle_use_cpuhp) + return; + + err = cpuhp_setup_state_nocalls(CPUHP_AP_CPU_PM_STARTING, + "cpuidle/psci:online", + psci_idle_cpuhp_up, + psci_idle_cpuhp_down); + if (err) + pr_warn("Failed %d while setup cpuhp state\n", err); +} + static int psci_enter_idle_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, int idx) { @@ -166,9 +206,11 @@ static int __init psci_dt_cpu_init_idle(struct cpuidle_driver *drv, * selection of a shared state for the domain, assumes the * domain states are all deeper states. */ - if (data->dev) + if (data->dev) { drv->states[state_count - 1].enter = psci_enter_domain_idle_state; + psci_cpuidle_use_cpuhp = true; + } } /* Idle states parsed correctly, store them in the per-cpu struct. */ @@ -289,6 +331,7 @@ static int __init psci_idle_init(void) goto out_fail; } + psci_idle_init_cpuhp(); return 0; out_fail: diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h index e51ee772b9f5..01f04ed6ad92 100644 --- a/include/linux/cpuhotplug.h +++ b/include/linux/cpuhotplug.h @@ -95,6 +95,7 @@ enum cpuhp_state { CPUHP_AP_OFFLINE, CPUHP_AP_SCHED_STARTING, CPUHP_AP_RCUTREE_DYING, + CPUHP_AP_CPU_PM_STARTING, CPUHP_AP_IRQ_GIC_STARTING, CPUHP_AP_IRQ_HIP04_STARTING, CPUHP_AP_IRQ_ARMADA_XP_STARTING,
When the hierarchical CPU topology is used and when a CPU is put offline, that CPU prevents its PM domain from being powered off, which is because genpd observes the corresponding attached device as being active from a runtime PM point of view. Furthermore, any potential master PM domains are also prevented from being powered off. To address this limitation, let's add add a new CPU hotplug state (CPUHP_AP_CPU_PM_STARTING) and register up/down callbacks for it, which allows us to deal with runtime PM accordingly. Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org> --- Changes in v4: - Folded in the patch to be part of the series. - Rebased on top of earlier changes. --- drivers/cpuidle/cpuidle-psci.c | 45 +++++++++++++++++++++++++++++++++- include/linux/cpuhotplug.h | 1 + 2 files changed, 45 insertions(+), 1 deletion(-) -- 2.17.1