From 12641505653f491f414406a1b5dd35876f61cfb8 Mon Sep 17 00:00:00 2001 From: Colin Cross Date: Mon, 7 May 2012 17:57:42 -0700 Subject: [PATCH] --- yaml --- r: 318810 b: refs/heads/master c: 20ff51a36b2cd25ee7eb3216b6d02b68935435ba h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/drivers/cpuidle/coupled.c | 37 +++++++++++++++++++++++++++++++++ trunk/include/linux/cpuidle.h | 4 ++++ 3 files changed, 42 insertions(+), 1 deletion(-) diff --git a/[refs] b/[refs] index 94f66c6105c4..3ad6c57c2c17 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 4126c0197bc8c58a0bb7fcda07b01b596b6fb4c5 +refs/heads/master: 20ff51a36b2cd25ee7eb3216b6d02b68935435ba diff --git a/trunk/drivers/cpuidle/coupled.c b/trunk/drivers/cpuidle/coupled.c index aab6bba8daec..2c9bf2692232 100644 --- a/trunk/drivers/cpuidle/coupled.c +++ b/trunk/drivers/cpuidle/coupled.c @@ -129,6 +129,43 @@ static DEFINE_PER_CPU(struct call_single_data, cpuidle_coupled_poke_cb); */ static cpumask_t cpuidle_coupled_poked_mask; +/** + * cpuidle_coupled_parallel_barrier - synchronize all online coupled cpus + * @dev: cpuidle_device of the calling cpu + * @a: atomic variable to hold the barrier + * + * No caller to this function will return from this function until all online + * cpus in the same coupled group have called this function. Once any caller + * has returned from this function, the barrier is immediately available for + * reuse. + * + * The atomic variable a must be initialized to 0 before any cpu calls + * this function, will be reset to 0 before any cpu returns from this function. + * + * Must only be called from within a coupled idle state handler + * (state.enter when state.flags has CPUIDLE_FLAG_COUPLED set). + * + * Provides full smp barrier semantics before and after calling. + */ +void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a) +{ + int n = dev->coupled->online_count; + + smp_mb__before_atomic_inc(); + atomic_inc(a); + + while (atomic_read(a) < n) + cpu_relax(); + + if (atomic_inc_return(a) == n * 2) { + atomic_set(a, 0); + return; + } + + while (atomic_read(a) > n) + cpu_relax(); +} + /** * cpuidle_state_is_coupled - check if a state is part of a coupled set * @dev: struct cpuidle_device for the current cpu diff --git a/trunk/include/linux/cpuidle.h b/trunk/include/linux/cpuidle.h index 603844835bc7..5ab7183313ce 100644 --- a/trunk/include/linux/cpuidle.h +++ b/trunk/include/linux/cpuidle.h @@ -183,6 +183,10 @@ static inline int cpuidle_play_dead(void) {return -ENODEV; } #endif +#ifdef CONFIG_ARCH_NEEDS_CPU_IDLE_COUPLED +void cpuidle_coupled_parallel_barrier(struct cpuidle_device *dev, atomic_t *a); +#endif + /****************************** * CPUIDLE GOVERNOR INTERFACE * ******************************/