linux/drivers/cpuidle
Daniel Lezcano e7387da520 cpuidle: Fix cpuidle_state_is_coupled() argument in cpuidle_enter()
Commit 0b89e9aa28 (cpuidle: delay enabling interrupts until all
coupled CPUs leave idle) rightfully fixed a regression by letting
the coupled idle state framework to handle local interrupt enabling
when the CPU is exiting an idle state.

The current code checks if the idle state is coupled and, if so, it
will let the coupled code to enable interrupts. This way, it can
decrement the ready-count before handling the interrupt. This
mechanism prevents the other CPUs from waiting for a CPU which is
handling interrupts.

But the check is done against the state index returned by the back
end driver's ->enter functions which could be different from the
initial index passed as parameter to the cpuidle_enter_state()
function.

 entered_state = target_state->enter(dev, drv, index);

 [ ... ]

 if (!cpuidle_state_is_coupled(drv, entered_state))
	local_irq_enable();

 [ ... ]

If the 'index' is referring to a coupled idle state but the
'entered_state' is *not* coupled, then the interrupts are enabled
again. All CPUs blocked on the sync barrier may busy loop longer
if the CPU has interrupts to handle before decrementing the
ready-count. That's consuming more energy than saving.

Fixes: 0b89e9aa28 (cpuidle: delay enabling interrupts until all coupled CPUs leave idle)
Signed-off-by: Daniel Lezcano <daniel.lezcano@linaro.org>
Cc: 3.15+ <stable@vger.kernel.org> # 3.15+
[ rjw: Subject & changelog ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2016-05-18 02:48:37 +02:00
..
governors cpuidle: menu: Fall back to polling if next timer event is near 2016-03-21 15:50:28 +01:00
coupled.c cpuidle: coupled: remove unused define cpuidle_coupled_lock 2016-01-27 23:08:46 +01:00
cpuidle-arm.c ARM: cpuidle: Pass on arm_cpuidle_suspend()'s return value 2016-04-28 15:15:14 +02:00
cpuidle-at91.c
cpuidle-big_little.c
cpuidle-calxeda.c
cpuidle-clps711x.c drivers/cpuidle: make cpuidle-clps711x.c explicitly non-modular 2015-12-15 00:22:21 +01:00
cpuidle-cps.c
cpuidle-exynos.c drivers/cpuidle: make cpuidle-exynos.c explicitly non-modular 2015-12-15 00:22:22 +01:00
cpuidle-kirkwood.c
cpuidle-mvebu-v7.c cpuidle: mvebu: disable the bind/unbind attributes and use builtin_platform_driver 2015-10-23 12:40:48 +02:00
cpuidle-powernv.c powerpc/powernv: remove FW_FEATURE_OPALv3 and just use FW_FEATURE_OPAL 2015-12-17 22:40:54 +11:00
cpuidle-pseries.c
cpuidle-ux500.c drivers/cpuidle: make cpuidle-ux500.c explicitly non-modular 2015-12-15 00:22:22 +01:00
cpuidle-zynq.c
cpuidle.c cpuidle: Fix cpuidle_state_is_coupled() argument in cpuidle_enter() 2016-05-18 02:48:37 +02:00
cpuidle.h cpuidle/coupled: Add sanity check for safe_state_index 2015-09-03 03:05:47 +02:00
driver.c cpuidle/coupled: Add sanity check for safe_state_index 2015-09-03 03:05:47 +02:00
dt_idle_states.c
dt_idle_states.h
governor.c
Kconfig cpuidle: Don't enable all governors by default 2016-01-15 22:39:58 +01:00
Kconfig.arm
Kconfig.mips
Kconfig.powerpc
Makefile
sysfs.c