cpuidle, tegra: Push RCU-idle into driver
authorPeter Zijlstra <peterz@infradead.org>
Thu, 12 Jan 2023 19:43:20 +0000 (20:43 +0100)
committerIngo Molnar <mingo@kernel.org>
Fri, 13 Jan 2023 10:03:22 +0000 (11:03 +0100)
Doing RCU-idle outside the driver, only to then temporarily enable it
again, at least twice, before going idle is suboptimal.

Notably once implicitly through the cpu_pm_*() calls and once
explicitly doing RCU_NONIDLE().

Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Tested-by: Tony Lindgren <tony@atomide.com>
Tested-by: Ulf Hansson <ulf.hansson@linaro.org>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Link: https://lore.kernel.org/r/20230112195539.699546331@infradead.org
drivers/cpuidle/cpuidle-tegra.c

index 9845629aeb6d404deb4a7b56e4319b3b8e7632ae..3ca5cfb9d322d2f72c8ae9330fb94b8d4df4d628 100644 (file)
@@ -180,9 +180,11 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev,
        }
 
        local_fiq_disable();
-       RCU_NONIDLE(tegra_pm_set_cpu_in_lp2());
+       tegra_pm_set_cpu_in_lp2();
        cpu_pm_enter();
 
+       ct_idle_enter();
+
        switch (index) {
        case TEGRA_C7:
                err = tegra_cpuidle_c7_enter();
@@ -197,8 +199,10 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev,
                break;
        }
 
+       ct_idle_exit();
+
        cpu_pm_exit();
-       RCU_NONIDLE(tegra_pm_clear_cpu_in_lp2());
+       tegra_pm_clear_cpu_in_lp2();
        local_fiq_enable();
 
        return err ?: index;
@@ -226,6 +230,7 @@ static int tegra_cpuidle_enter(struct cpuidle_device *dev,
                               struct cpuidle_driver *drv,
                               int index)
 {
+       bool do_rcu = drv->states[index].flags & CPUIDLE_FLAG_RCU_IDLE;
        unsigned int cpu = cpu_logical_map(dev->cpu);
        int ret;
 
@@ -233,9 +238,13 @@ static int tegra_cpuidle_enter(struct cpuidle_device *dev,
        if (dev->states_usage[index].disable)
                return -1;
 
-       if (index == TEGRA_C1)
+       if (index == TEGRA_C1) {
+               if (do_rcu)
+                       ct_idle_enter();
                ret = arm_cpuidle_simple_enter(dev, drv, index);
-       else
+               if (do_rcu)
+                       ct_idle_exit();
+       } else
                ret = tegra_cpuidle_state_enter(dev, index, cpu);
 
        if (ret < 0) {
@@ -285,7 +294,8 @@ static struct cpuidle_driver tegra_idle_driver = {
                        .exit_latency           = 2000,
                        .target_residency       = 2200,
                        .power_usage            = 100,
-                       .flags                  = CPUIDLE_FLAG_TIMER_STOP,
+                       .flags                  = CPUIDLE_FLAG_TIMER_STOP |
+                                                 CPUIDLE_FLAG_RCU_IDLE,
                        .name                   = "C7",
                        .desc                   = "CPU core powered off",
                },
@@ -295,6 +305,7 @@ static struct cpuidle_driver tegra_idle_driver = {
                        .target_residency       = 10000,
                        .power_usage            = 0,
                        .flags                  = CPUIDLE_FLAG_TIMER_STOP |
+                                                 CPUIDLE_FLAG_RCU_IDLE   |
                                                  CPUIDLE_FLAG_COUPLED,
                        .name                   = "CC6",
                        .desc                   = "CPU cluster powered off",