Merge tag 'for-linus-5.11-rc1-tag' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / cpuidle / cpuidle-psci.c
index d928b37..b51b5df 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/psci.h>
+#include <linux/pm_domain.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <linux/string.h>
@@ -52,8 +53,9 @@ static inline int psci_enter_state(int idx, u32 state)
        return CPU_PM_CPU_IDLE_ENTER_PARAM(psci_cpu_suspend_enter, idx, state);
 }
 
-static int psci_enter_domain_idle_state(struct cpuidle_device *dev,
-                                       struct cpuidle_driver *drv, int idx)
+static int __psci_enter_domain_idle_state(struct cpuidle_device *dev,
+                                         struct cpuidle_driver *drv, int idx,
+                                         bool s2idle)
 {
        struct psci_cpuidle_data *data = this_cpu_ptr(&psci_cpuidle_data);
        u32 *states = data->psci_states;
@@ -66,7 +68,12 @@ static int psci_enter_domain_idle_state(struct cpuidle_device *dev,
                return -1;
 
        /* Do runtime PM to manage a hierarchical CPU toplogy. */
-       RCU_NONIDLE(pm_runtime_put_sync_suspend(pd_dev));
+       rcu_irq_enter_irqson();
+       if (s2idle)
+               dev_pm_genpd_suspend(pd_dev);
+       else
+               pm_runtime_put_sync_suspend(pd_dev);
+       rcu_irq_exit_irqson();
 
        state = psci_get_domain_state();
        if (!state)
@@ -74,7 +81,12 @@ static int psci_enter_domain_idle_state(struct cpuidle_device *dev,
 
        ret = psci_cpu_suspend_enter(state) ? -1 : idx;
 
-       RCU_NONIDLE(pm_runtime_get_sync(pd_dev));
+       rcu_irq_enter_irqson();
+       if (s2idle)
+               dev_pm_genpd_resume(pd_dev);
+       else
+               pm_runtime_get_sync(pd_dev);
+       rcu_irq_exit_irqson();
 
        cpu_pm_exit();
 
@@ -83,6 +95,19 @@ static int psci_enter_domain_idle_state(struct cpuidle_device *dev,
        return ret;
 }
 
+static int psci_enter_domain_idle_state(struct cpuidle_device *dev,
+                                       struct cpuidle_driver *drv, int idx)
+{
+       return __psci_enter_domain_idle_state(dev, drv, idx, false);
+}
+
+static int psci_enter_s2idle_domain_idle_state(struct cpuidle_device *dev,
+                                              struct cpuidle_driver *drv,
+                                              int idx)
+{
+       return __psci_enter_domain_idle_state(dev, drv, idx, true);
+}
+
 static int psci_idle_cpuhp_up(unsigned int cpu)
 {
        struct device *pd_dev = __this_cpu_read(psci_cpuidle_data.dev);
@@ -170,6 +195,7 @@ static int psci_dt_cpu_init_topology(struct cpuidle_driver *drv,
         * deeper states.
         */
        drv->states[state_count - 1].enter = psci_enter_domain_idle_state;
+       drv->states[state_count - 1].enter_s2idle = psci_enter_s2idle_domain_idle_state;
        psci_cpuidle_use_cpuhp = true;
 
        return 0;