Skip to content

Commit 1966aaa

Browse files
committed
cpuidle: Mark CPUs idle as late as possible to avoid unneeded IPIs
It isn't guaranteed a CPU will idle upon calling lpm_cpuidle_enter(), since it could abort early at the need_resched() check. In this case, it's possible for an IPI to be sent to this "idle" CPU needlessly, thus wasting power. For the same reason, it's also wasteful to keep a CPU marked idle even after it's woken up. Reduce the window that CPUs are marked idle to as small as it can be in order to improve power consumption. Signed-off-by: Sultan Alsawaf <[email protected]>
1 parent 41937e5 commit 1966aaa

File tree

3 files changed

+12
-7
lines changed

3 files changed

+12
-7
lines changed

drivers/cpuidle/cpuidle.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,15 @@ static atomic_t idled = ATOMIC_INIT(0);
4242
#error idled CPU mask not big enough for NR_CPUS
4343
#endif
4444

45-
static void cpuidle_set_idle_cpu(unsigned int cpu)
45+
void cpuidle_set_idle_cpu(unsigned int cpu)
4646
{
4747
atomic_or(BIT(cpu), &idled);
4848
}
4949

50-
static void cpuidle_clear_idle_cpu(unsigned int cpu)
50+
void cpuidle_clear_idle_cpu(unsigned int cpu)
5151
{
5252
atomic_andnot(BIT(cpu), &idled);
5353
}
54-
#else
55-
static inline void cpuidle_set_idle_cpu(unsigned int cpu) { }
56-
static inline void cpuidle_clear_idle_cpu(unsigned int cpu) { }
5754
#endif
5855

5956
int cpuidle_disabled(void)
@@ -220,9 +217,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
220217
time_start = ktime_get();
221218

222219
stop_critical_timings();
223-
cpuidle_set_idle_cpu(dev->cpu);
224220
entered_state = target_state->enter(dev, drv, index);
225-
cpuidle_clear_idle_cpu(dev->cpu);
226221
start_critical_timings();
227222

228223
time_end = ktime_get();

drivers/cpuidle/lpm-levels.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,7 +1506,9 @@ static int lpm_cpuidle_enter(struct cpuidle_device *dev,
15061506
goto exit;
15071507

15081508
BUG_ON(!use_psci);
1509+
cpuidle_set_idle_cpu(dev->cpu);
15091510
success = psci_enter_sleep(cluster, idx, true);
1511+
cpuidle_clear_idle_cpu(dev->cpu);
15101512

15111513
exit:
15121514
end_time = ktime_to_ns(ktime_get());

include/linux/cpuidle.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,4 +252,12 @@ static inline int cpuidle_register_governor(struct cpuidle_governor *gov)
252252
#define CPUIDLE_DRIVER_STATE_START 0
253253
#endif
254254

255+
#ifdef CONFIG_SMP
256+
void cpuidle_set_idle_cpu(unsigned int cpu);
257+
void cpuidle_clear_idle_cpu(unsigned int cpu);
258+
#else
259+
static inline void cpuidle_set_idle_cpu(unsigned int cpu) { }
260+
static inline void cpuidle_clear_idle_cpu(unsigned int cpu) { }
261+
#endif
262+
255263
#endif /* _LINUX_CPUIDLE_H */

0 commit comments

Comments
 (0)