History

cpuidle: Fix ct_idle_*() usage

The whole disable-RCU, enable-IRQS dance is very intricate since changing IRQ state is traced, which depends on RCU. Add two helpers for the cpuidle case that mirror the entry code: ct_cpuidle_enter() ct_cpuidle_exit() And fix all the cases where the enter/exit dance was buggy.

Peter Zijlstra committed 3 years ago

Commit a01353c1 parent 0c5ffc315 files · +86 −66Browse files

Unified · Split

15 files
  1. arch/arm/mach-imx/cpuidle-imx6q.c +2 −2
  2. arch/arm/mach-imx/cpuidle-imx6sx.c +2 −2
  3. arch/arm/mach-omap2/cpuidle34xx.c +2 −2
  4. arch/arm/mach-omap2/cpuidle44xx.c +4 −4
  5. drivers/acpi/processor_idle.c +6 −2
  6. drivers/cpuidle/cpuidle-big_little.c +2 −2
  7. drivers/cpuidle/cpuidle-mvebu-v7.c +2 −2
  8. drivers/cpuidle/cpuidle-psci.c +2 −2
  9. drivers/cpuidle/cpuidle-riscv-sbi.c +2 −2
  10. drivers/cpuidle/cpuidle-tegra.c +4 −4
  11. drivers/cpuidle/cpuidle.c +6 −5
  12. include/linux/clockchips.h +2 −2
  13. include/linux/cpuidle.h +32 −2
  14. kernel/sched/idle.c +13 −32
  15. kernel/time/tick-broadcast.c +5 −1
arch/arm/mach-imx/cpuidle-imx6q.c+2−2
@@ -25,9 +25,9 @@ static int imx6q_enter_wait(struct cpuidle_device *dev, · 24 unmodified lines
2525 imx6_set_lpm(WAIT_UNCLOCKED);
2626 raw_spin_unlock(&cpuidle_lock);
2727
28− ct_idle_enter();
28+ ct_cpuidle_enter();
2929 cpu_do_idle();
30− ct_idle_exit();
30+ ct_cpuidle_exit();
3131
3232 raw_spin_lock(&cpuidle_lock);
3333 if (num_idle_cpus-- == num_online_cpus())
arch/arm/mach-imx/cpuidle-imx6sx.c+2−2
@@ -47,9 +47,9 @@ static int imx6sx_enter_wait(struct cpuidle_device *dev, · 46 unmodified lines
4747 cpu_pm_enter();
4848 cpu_cluster_pm_enter();
4949
50− ct_idle_enter();
50+ ct_cpuidle_enter();
5151 cpu_suspend(0, imx6sx_idle_finish);
52− ct_idle_exit();
52+ ct_cpuidle_exit();
5353
5454 cpu_cluster_pm_exit();
5555 cpu_pm_exit();
arch/arm/mach-omap2/cpuidle34xx.c+2−2
@@ -133,9 +133,9 @@ static int omap3_enter_idle(struct cpuidle_device *dev, · 132 unmodified lines
133133 }
134134
135135 /* Execute ARM wfi */
136− ct_idle_enter();
136+ ct_cpuidle_enter();
137137 omap_sram_idle();
138− ct_idle_exit();
138+ ct_cpuidle_exit();
139139
140140 /*
141141 * Call idle CPU PM enter notifier chain to restore
arch/arm/mach-omap2/cpuidle44xx.c+4−4
@@ -105,9 +105,9 @@ static int omap_enter_idle_smp(struct cpuidle_device *dev, · 104 unmodified lines
105105 }
106106 raw_spin_unlock_irqrestore(&mpu_lock, flag);
107107
108− ct_idle_enter();
108+ ct_cpuidle_enter();
109109 omap4_enter_lowpower(dev->cpu, cx->cpu_state);
110− ct_idle_exit();
110+ ct_cpuidle_exit();
111111
112112 raw_spin_lock_irqsave(&mpu_lock, flag);
113113 if (cx->mpu_state_vote == num_online_cpus())
@@ -186,10 +186,10 @@ static int omap_enter_idle_coupled(struct cpuidle_device *dev, · 72 unmodified lines
186186 }
187187 }
188188
189− ct_idle_enter();
189+ ct_cpuidle_enter();
190190 omap4_enter_lowpower(dev->cpu, cx->cpu_state);
191191 cpu_done[dev->cpu] = true;
192− ct_idle_exit();
192+ ct_cpuidle_exit();
193193
194194 /* Wakeup CPU1 only if it is not offlined */
195195 if (dev->cpu == 0 && cpumask_test_cpu(1, cpu_online_mask)) {
drivers/acpi/processor_idle.c+6−2
@@ -642,6 +642,8 @@ static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, · 641 unmodified lines
642642 */
643643 bool dis_bm = pr->flags.bm_control;
644644
645+ instrumentation_begin();
646+
645647 /* If we can skip BM, demote to a safe state. */
646648 if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
647649 dis_bm = false;
@@ -663,11 +665,11 @@ static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, · 15 unmodified lines
663665 raw_spin_unlock(&c3_lock);
664666 }
665667
666− ct_idle_enter();
668+ ct_cpuidle_enter();
667669
668670 acpi_idle_do_entry(cx);
669671
670− ct_idle_exit();
672+ ct_cpuidle_exit();
671673
672674 /* Re-enable bus master arbitration */
673675 if (dis_bm) {
@@ -677,6 +679,8 @@ static int __cpuidle acpi_idle_enter_bm(struct cpuidle_driver *drv, · 3 unmodified lines
677679 raw_spin_unlock(&c3_lock);
678680 }
679681
682+ instrumentation_end();
683+
680684 return index;
681685 }
682686
drivers/cpuidle/cpuidle-big_little.c+2−2
@@ -126,13 +126,13 @@ static int bl_enter_powerdown(struct cpuidle_device *dev, · 125 unmodified lines
126126 struct cpuidle_driver *drv, int idx)
127127 {
128128 cpu_pm_enter();
129− ct_idle_enter();
129+ ct_cpuidle_enter();
130130
131131 cpu_suspend(0, bl_powerdown_finisher);
132132
133133 /* signals the MCPM core that CPU is out of low power state */
134134 mcpm_cpu_powered_up();
135− ct_idle_exit();
135+ ct_cpuidle_exit();
136136
137137 cpu_pm_exit();
138138
drivers/cpuidle/cpuidle-mvebu-v7.c+2−2
@@ -36,9 +36,9 @@ static int mvebu_v7_enter_idle(struct cpuidle_device *dev, · 35 unmodified lines
3636 if (drv->states[index].flags & MVEBU_V7_FLAG_DEEP_IDLE)
3737 deepidle = true;
3838
39− ct_idle_enter();
39+ ct_cpuidle_enter();
4040 ret = mvebu_v7_cpu_suspend(deepidle);
41− ct_idle_exit();
41+ ct_cpuidle_exit();
4242
4343 cpu_pm_exit();
4444
drivers/cpuidle/cpuidle-psci.c+2−2
@@ -74,7 +74,7 @@ static int __psci_enter_domain_idle_state(struct cpuidle_device *dev, · 73 unmodified lines
7474 else
7575 pm_runtime_put_sync_suspend(pd_dev);
7676
77− ct_idle_enter();
77+ ct_cpuidle_enter();
7878
7979 state = psci_get_domain_state();
8080 if (!state)
@@ -82,7 +82,7 @@ static int __psci_enter_domain_idle_state(struct cpuidle_device *dev, · 1 unmodified line
8282
8383 ret = psci_cpu_suspend_enter(state) ? -1 : idx;
8484
85− ct_idle_exit();
85+ ct_cpuidle_exit();
8686
8787 if (s2idle)
8888 dev_pm_genpd_resume(pd_dev);
drivers/cpuidle/cpuidle-riscv-sbi.c+2−2
@@ -126,7 +126,7 @@ static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev, · 125 unmodified lines
126126 else
127127 pm_runtime_put_sync_suspend(pd_dev);
128128
129− ct_idle_enter();
129+ ct_cpuidle_enter();
130130
131131 if (sbi_is_domain_state_available())
132132 state = sbi_get_domain_state();
@@ -135,7 +135,7 @@ static int __sbi_enter_domain_idle_state(struct cpuidle_device *dev, · 2 unmodified lines
135135
136136 ret = sbi_suspend(state) ? -1 : idx;
137137
138− ct_idle_exit();
138+ ct_cpuidle_exit();
139139
140140 if (s2idle)
141141 dev_pm_genpd_resume(pd_dev);
drivers/cpuidle/cpuidle-tegra.c+4−4
@@ -183,7 +183,7 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, · 182 unmodified lines
183183 tegra_pm_set_cpu_in_lp2();
184184 cpu_pm_enter();
185185
186− ct_idle_enter();
186+ ct_cpuidle_enter();
187187
188188 switch (index) {
189189 case TEGRA_C7:
@@ -199,7 +199,7 @@ static int tegra_cpuidle_state_enter(struct cpuidle_device *dev, · 9 unmodified lines
199199 break;
200200 }
201201
202− ct_idle_exit();
202+ ct_cpuidle_exit();
203203
204204 cpu_pm_exit();
205205 tegra_pm_clear_cpu_in_lp2();
@@ -240,10 +240,10 @@ static int tegra_cpuidle_enter(struct cpuidle_device *dev, · 34 unmodified lines
240240
241241 if (index == TEGRA_C1) {
242242 if (do_rcu)
243− ct_idle_enter();
243+ ct_cpuidle_enter();
244244 ret = arm_cpuidle_simple_enter(dev, drv, index);
245245 if (do_rcu)
246− ct_idle_exit();
246+ ct_cpuidle_exit();
247247 } else
248248 ret = tegra_cpuidle_state_enter(dev, index, cpu);
249249
drivers/cpuidle/cpuidle.c+6−5
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #include <linux/mutex.h>
1515 #include <linux/sched.h>
1616 #include <linux/sched/clock.h>
17+#include <linux/sched/idle.h>
1718 #include <linux/notifier.h>
1819 #include <linux/pm_qos.h>
1920 #include <linux/cpu.h>
@@ -152,12 +153,12 @@ static void enter_s2idle_proper(struct cpuidle_driver *drv, · 132 unmodified lines
152153 */
153154 stop_critical_timings();
154155 if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
155− ct_idle_enter();
156+ ct_cpuidle_enter();
156157 target_state->enter_s2idle(dev, drv, index);
157158 if (WARN_ON_ONCE(!irqs_disabled()))
158− local_irq_disable();
159+ raw_local_irq_disable();
159160 if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
160− ct_idle_exit();
161+ ct_cpuidle_exit();
161162 tick_unfreeze();
162163 start_critical_timings();
163164
@@ -235,14 +236,14 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, · 71 unmodified lines
235236
236237 stop_critical_timings();
237238 if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
238− ct_idle_enter();
239+ ct_cpuidle_enter();
239240
240241 entered_state = target_state->enter(dev, drv, index);
241242 if (WARN_ONCE(!irqs_disabled(), "%ps leaked IRQ state", target_state->enter))
242243 raw_local_irq_disable();
243244
244245 if (!(target_state->flags & CPUIDLE_FLAG_RCU_IDLE))
245− ct_idle_exit();
246+ ct_cpuidle_exit();
246247 start_critical_timings();
247248
248249 sched_clock_idle_wakeup_event();
include/linux/clockchips.h+2−2
@@ -211,7 +211,7 @@ extern int tick_receive_broadcast(void); · 210 unmodified lines
211211 extern void tick_setup_hrtimer_broadcast(void);
212212 extern int tick_check_broadcast_expired(void);
213213 # else
214−static inline int tick_check_broadcast_expired(void) { return 0; }
214+static __always_inline int tick_check_broadcast_expired(void) { return 0; }
215215 static inline void tick_setup_hrtimer_broadcast(void) { }
216216 # endif
217217
@@ -219,7 +219,7 @@ static inline void tick_setup_hrtimer_broadcast(void) { } · 1 unmodified line
219219
220220 static inline void clockevents_suspend(void) { }
221221 static inline void clockevents_resume(void) { }
222−static inline int tick_check_broadcast_expired(void) { return 0; }
222+static __always_inline int tick_check_broadcast_expired(void) { return 0; }
223223 static inline void tick_setup_hrtimer_broadcast(void) { }
224224
225225 #endif /* !CONFIG_GENERIC_CLOCKEVENTS */
include/linux/cpuidle.h+32−2
@@ -14,6 +14,7 @@ · 13 unmodified lines
1414 #include <linux/percpu.h>
1515 #include <linux/list.h>
1616 #include <linux/hrtimer.h>
17+#include <linux/context_tracking.h>
1718
1819 #define CPUIDLE_STATE_MAX 10
1920 #define CPUIDLE_NAME_LEN 16
@@ -115,6 +116,35 @@ struct cpuidle_device { · 95 unmodified lines
115116 DECLARE_PER_CPU(struct cpuidle_device *, cpuidle_devices);
116117 DECLARE_PER_CPU(struct cpuidle_device, cpuidle_dev);
117118
119+static __always_inline void ct_cpuidle_enter(void)
120+{
121+ lockdep_assert_irqs_disabled();
122+ /*
123+ * Idle is allowed to (temporary) enable IRQs. It
124+ * will return with IRQs disabled.
125+ *
126+ * Trace IRQs enable here, then switch off RCU, and have
127+ * arch_cpu_idle() use raw_local_irq_enable(). Note that
128+ * ct_idle_enter() relies on lockdep IRQ state, so switch that
129+ * last -- this is very similar to the entry code.
130+ */
131+ trace_hardirqs_on_prepare();
132+ lockdep_hardirqs_on_prepare();
133+ instrumentation_end();
134+ ct_idle_enter();
135+ lockdep_hardirqs_on(_RET_IP_);
136+}
137+
138+static __always_inline void ct_cpuidle_exit(void)
139+{
140+ /*
141+ * Carefully undo the above.
142+ */
143+ lockdep_hardirqs_off(_RET_IP_);
144+ ct_idle_exit();
145+ instrumentation_begin();
146+}
147+
118148 /****************************
119149 * CPUIDLE DRIVER INTERFACE *
120150 ****************************/
@@ -289,9 +319,9 @@ extern s64 cpuidle_governor_latency_req(unsigned int cpu); · 168 unmodified lines
289319 if (!is_retention) \
290320 __ret = cpu_pm_enter(); \
291321 if (!__ret) { \
292− ct_idle_enter(); \
322+ ct_cpuidle_enter(); \
293323 __ret = low_level_idle_enter(state); \
294− ct_idle_exit(); \
324+ ct_cpuidle_exit(); \
295325 if (!is_retention) \
296326 cpu_pm_exit(); \
297327 } \
kernel/sched/idle.c+13−32
@@ -51,18 +51,22 @@ __setup("hlt", cpu_idle_nopoll_setup); · 50 unmodified lines
5151
5252 static noinline int __cpuidle cpu_idle_poll(void)
5353 {
54+ instrumentation_begin();
5455 trace_cpu_idle(0, smp_processor_id());
5556 stop_critical_timings();
56− ct_idle_enter();
57− local_irq_enable();
57+ ct_cpuidle_enter();
5858
59+ raw_local_irq_enable();
5960 while (!tif_need_resched() &&
6061 (cpu_idle_force_poll || tick_check_broadcast_expired()))
6162 cpu_relax();
63+ raw_local_irq_disable();
6264
63− ct_idle_exit();
65+ ct_cpuidle_exit();
6466 start_critical_timings();
6567 trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
68+ local_irq_enable();
69+ instrumentation_end();
6670
6771 return 1;
6872 }
@@ -85,44 +89,21 @@ void __weak arch_cpu_idle(void) · 16 unmodified lines
8589 */
8690 void __cpuidle default_idle_call(void)
8791 {
88− if (current_clr_polling_and_test()) {
89− local_irq_enable();
90− } else {
91−
92+ instrumentation_begin();
93+ if (!current_clr_polling_and_test()) {
9294 trace_cpu_idle(1, smp_processor_id());
9395 stop_critical_timings();
9496
95− /*
96− * arch_cpu_idle() is supposed to enable IRQs, however
97− * we can't do that because of RCU and tracing.
98− *
99− * Trace IRQs enable here, then switch off RCU, and have
100− * arch_cpu_idle() use raw_local_irq_enable(). Note that
101− * ct_idle_enter() relies on lockdep IRQ state, so switch that
102− * last -- this is very similar to the entry code.
103− */
104− trace_hardirqs_on_prepare();
105− lockdep_hardirqs_on_prepare();
106− ct_idle_enter();
107− lockdep_hardirqs_on(_THIS_IP_);
108−
97+ ct_cpuidle_enter();
10998 arch_cpu_idle();
110−
111− /*
112− * OK, so IRQs are enabled here, but RCU needs them disabled to
113− * turn itself back on.. funny thing is that disabling IRQs
114− * will cause tracing, which needs RCU. Jump through hoops to
115− * make it 'work'.
116− */
11799 raw_local_irq_disable();
118− lockdep_hardirqs_off(_THIS_IP_);
119− ct_idle_exit();
120− lockdep_hardirqs_on(_THIS_IP_);
121− raw_local_irq_enable();
100+ ct_cpuidle_exit();
122101
123102 start_critical_timings();
124103 trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
125104 }
105+ local_irq_enable();
106+ instrumentation_end();
126107 }
127108
128109 static int call_cpuidle_s2idle(struct cpuidle_driver *drv,
kernel/time/tick-broadcast.c+5−1
@@ -622,9 +622,13 @@ struct cpumask *tick_get_broadcast_oneshot_mask(void) · 621 unmodified lines
622622 * to avoid a deep idle transition as we are about to get the
623623 * broadcast IPI right away.
624624 */
625−int tick_check_broadcast_expired(void)
625+noinstr int tick_check_broadcast_expired(void)
626626 {
627+#ifdef _ASM_GENERIC_BITOPS_INSTRUMENTED_NON_ATOMIC_H
628+ return arch_test_bit(smp_processor_id(), cpumask_bits(tick_broadcast_force_mask));
629+#else
627630 return cpumask_test_cpu(smp_processor_id(), tick_broadcast_force_mask);
631+#endif
628632 }
629633
630634 /*