Skip to content

Commit e9aec64

Browse files
authored
Deny Idle entry of CPU and CPU domain when it already has IPI pending (#444)
Deny Idle entry of CPU and CPU domain when it already has IPI pending
2 parents c9922dc + 3caa15b commit e9aec64

4 files changed

Lines changed: 43 additions & 7 deletions

File tree

drivers/cpuidle/cpuidle.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,9 @@ noinstr int cpuidle_enter_state(struct cpuidle_device *dev,
222222
bool broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP);
223223
ktime_t time_start, time_end;
224224

225+
if (cpus_peek_for_pending_ipi(cpumask_of(dev->cpu)))
226+
return -EBUSY;
227+
225228
instrumentation_begin();
226229

227230
/*

drivers/pmdomain/governor.c

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -404,15 +404,21 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
404404
if ((idle_duration_ns >= (genpd->states[i].residency_ns +
405405
genpd->states[i].power_off_latency_ns)) &&
406406
(global_constraint >= (genpd->states[i].power_on_latency_ns +
407-
genpd->states[i].power_off_latency_ns))) {
408-
genpd->state_idx = i;
409-
genpd->gd->last_enter = now;
410-
genpd->gd->reflect_residency = true;
411-
return true;
412-
}
407+
genpd->states[i].power_off_latency_ns)))
408+
break;
409+
413410
} while (--i >= 0);
414411

415-
return false;
412+
if (i < 0)
413+
return false;
414+
415+
if (cpus_peek_for_pending_ipi(genpd->cpus))
416+
return false;
417+
418+
genpd->state_idx = i;
419+
genpd->gd->last_enter = now;
420+
genpd->gd->reflect_residency = true;
421+
return true;
416422
}
417423

418424
struct dev_power_governor pm_domain_cpu_gov = {

include/linux/smp.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ int smp_call_function_any(const struct cpumask *mask,
168168

169169
void kick_all_cpus_sync(void);
170170
void wake_up_all_idle_cpus(void);
171+
bool cpus_peek_for_pending_ipi(const struct cpumask *mask);
171172

172173
/*
173174
* Generic and arch helpers
@@ -216,6 +217,10 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func,
216217

217218
static inline void kick_all_cpus_sync(void) { }
218219
static inline void wake_up_all_idle_cpus(void) { }
220+
static inline bool cpus_peek_for_pending_ipi(const struct cpumask *mask)
221+
{
222+
return false;
223+
}
219224

220225
#define setup_max_cpus 0
221226

kernel/smp.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,28 @@ void wake_up_all_idle_cpus(void)
10871087
}
10881088
EXPORT_SYMBOL_GPL(wake_up_all_idle_cpus);
10891089

1090+
/**
1091+
* cpus_peek_for_pending_ipi - Check for pending IPI for CPUs
1092+
* @mask: The CPU mask for the CPUs to check.
1093+
*
1094+
* This function walks through the @mask to check if there are any pending IPIs
1095+
* scheduled, for any of the CPUs in the @mask. It does not guarantee
1096+
* correctness as it only provides a racy snapshot.
1097+
*
1098+
* Returns true if there is a pending IPI scheduled and false otherwise.
1099+
*/
1100+
bool cpus_peek_for_pending_ipi(const struct cpumask *mask)
1101+
{
1102+
unsigned int cpu;
1103+
1104+
for_each_cpu(cpu, mask) {
1105+
if (!llist_empty(per_cpu_ptr(&call_single_queue, cpu)))
1106+
return true;
1107+
}
1108+
1109+
return false;
1110+
}
1111+
10901112
/**
10911113
* struct smp_call_on_cpu_struct - Call a function on a specific CPU
10921114
* @work: &work_struct

0 commit comments

Comments
 (0)