Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions drivers/cpuidle/cpuidle.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,9 @@ noinstr int cpuidle_enter_state(struct cpuidle_device *dev,
bool broadcast = !!(target_state->flags & CPUIDLE_FLAG_TIMER_STOP);
ktime_t time_start, time_end;

if (cpus_peek_for_pending_ipi(cpumask_of(dev->cpu)))
return -EBUSY;

instrumentation_begin();

/*
Expand Down
20 changes: 13 additions & 7 deletions drivers/pmdomain/governor.c
Original file line number Diff line number Diff line change
Expand Up @@ -404,15 +404,21 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
if ((idle_duration_ns >= (genpd->states[i].residency_ns +
genpd->states[i].power_off_latency_ns)) &&
(global_constraint >= (genpd->states[i].power_on_latency_ns +
genpd->states[i].power_off_latency_ns))) {
genpd->state_idx = i;
genpd->gd->last_enter = now;
genpd->gd->reflect_residency = true;
return true;
}
genpd->states[i].power_off_latency_ns)))
break;

} while (--i >= 0);

return false;
if (i < 0)
return false;

if (cpus_peek_for_pending_ipi(genpd->cpus))
return false;

genpd->state_idx = i;
genpd->gd->last_enter = now;
genpd->gd->reflect_residency = true;
return true;
}

struct dev_power_governor pm_domain_cpu_gov = {
Expand Down
5 changes: 5 additions & 0 deletions include/linux/smp.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ int smp_call_function_any(const struct cpumask *mask,

void kick_all_cpus_sync(void);
void wake_up_all_idle_cpus(void);
bool cpus_peek_for_pending_ipi(const struct cpumask *mask);

/*
* Generic and arch helpers
Expand Down Expand Up @@ -216,6 +217,10 @@ smp_call_function_any(const struct cpumask *mask, smp_call_func_t func,

static inline void kick_all_cpus_sync(void) { }
static inline void wake_up_all_idle_cpus(void) { }
static inline bool cpus_peek_for_pending_ipi(const struct cpumask *mask)
{
return false;
}

#define setup_max_cpus 0

Expand Down
22 changes: 22 additions & 0 deletions kernel/smp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1087,6 +1087,28 @@ void wake_up_all_idle_cpus(void)
}
EXPORT_SYMBOL_GPL(wake_up_all_idle_cpus);

/**
* cpus_peek_for_pending_ipi - Check for pending IPI for CPUs
* @mask: The CPU mask for the CPUs to check.
*
* This function walks through the @mask to check if there are any pending IPIs
* scheduled, for any of the CPUs in the @mask. It does not guarantee
* correctness as it only provides a racy snapshot.
*
* Returns true if there is a pending IPI scheduled and false otherwise.
*/
bool cpus_peek_for_pending_ipi(const struct cpumask *mask)
{
unsigned int cpu;

for_each_cpu(cpu, mask) {
if (!llist_empty(per_cpu_ptr(&call_single_queue, cpu)))
return true;
}

return false;
}

/**
* struct smp_call_on_cpu_struct - Call a function on a specific CPU
* @work: &work_struct
Expand Down